Frequency analysis (structsolve.freq)#
- structsolve.freq(K, M, tol=0, sparse_solver=True, silent=False, sort=True, num_eigvalues=25, num_eigvalues_print=5, skip_null_cols=False, symmetric=False, check_rtol=1e-06, max_dense_size=2000, linear_solver='splu')#
Frequency analysis
Calculates the eigenvalues
lambda2and eigenvectorsuof the free-vibration problem ofKandM, i.e. the eigenpairs with(K + lambda2*M) @ u = 0, wherelambda2 = -omega_n**2andomega_nis the natural frequency in rad/s. The null rows and columns ofKare removed from both matrices before solving the eigenvalue problem, unlessskip_null_cols=True.Solver policy. As in
lb(), withsparse_solver=Truethe sparse solver runs first for every problem size, and its eigenpairs are verified:the relative residual of each eigenpair must not be larger than
check_rtol, unless its backward error is at the round-off, seecheck_rtol;with
symmetric=True, no eigenvalueomega_n**2lower than the highest one returned may be missing, see_check_freq().
When the verification fails or the sparse solver raises an error, e.g. ARPACK did not converge, the dense solver is used as a last resort if the problem has at most
max_dense_sizedofs, with alinear_buckling.DenseFallbackWarninggiving the reasons. It returns thenum_eigvalueslowest eigenvalues withsymmetric=True, otherwise thenum_eigvalueseigenvalues closest to the shift, as the sparse solver, and its eigenpairs are verified as well. Otherwise aRuntimeErroris raised. Until version 0.5.3, the sparse solver only issued a warning when the residual check failed.With Intel MKL 2024.2.0 to 2025.0.0,
ncvofscipy.sparse.linalg.eigsh()is capped, seelb()andstructsolve.arpackutils.- Parameters:
- Ksparse_matrix
Stiffness matrix. Should include initial stress stiffness matrix, aerodynamic matrix and so forth when applicable.
- Msparse_matrix
Mass matrix.
- tolfloat, optional
A tolerance value passed to
scipy.sparse.linalg.eigs()andscipy.sparse.linalg.eigsh().- sparse_solverbool, optional
With
True, the default, the sparse solver always runs first, whatever the size of the problem:scipy.sparse.linalg.eigs(), orscipy.sparse.linalg.eigsh()withsymmetric=True, in shift-invert mode with a negative shift estimated from the matrices, calculating thenum_eigvalueseigenvalues closest to the shift. Its eigenpairs are verified, and a dense solver is only used as a last resort, see above. WithFalse, the full problem is explicitly solved with a dense solver,scipy.linalg.eig(), orscipy.linalg.eigh()withsymmetric=True, without trying the sparse solver, which calculates all eigenvalues, e.g. for the kinetic criterion of stability, and is a reference for validations.- silentbool, optional
A boolean to tell whether the log messages should be printed.
- sortbool, optional
Sort the eigenvalues and the eigenvectors together by increasing natural frequency, keeping only those with a natural frequency larger than
1e-6rad/s, e.g. without the rigid-body modes. The sort key is the real part of \(\omega_n = \sqrt{-\lambda^2}\) rounded to one decimal, then its imaginary part rounded to one decimal, then, between equal rounded keys, the exact real and imaginary parts of \(\omega_n\), then those of \(\omega_n^2 = -\lambda^2\), which separate two \(\omega_n^2\) differing at the round-off that have the same \(\omega_n\) after the square root. Only identical eigenvalues keep the order of the solver, such that a multiple eigenvalue returned with round-off differences, in an order that may depend on the LAPACK build, is sorted by increasing exact value. WithFalsethe eigenpairs are returned in the order of the solver. Until version 0.8.0, only the eigenvectors were sorted and filtered, and the eigenpairs with equal rounded keys kept the order of the solver.- num_eigvaluesint, optional
Number of calculated eigenvalues with the sparse solver, limited to the size of
Mminus 2.- num_eigvalues_printint, optional
Number of eigenvalues to print.
- skip_null_colsbool, optional
If True, skip the removal of null columns from the matrices. Use only when
KandMare known to be non-singular.- symmetricbool or None, optional
False, the default, uses the general solvers described above, valid for unsymmetric matrices, e.g.Kwith an aerodynamic matrix or with the load stiffness of follower loads.Trueuses the solvers of symmetric matrices,scipy.sparse.linalg.eigsh()in shift-invert mode orscipy.linalg.eigh(), which require symmetricKandMand a positive definiteM, and return real eigenvalues and eigenvectors normalized with respect toM.Noneselects them whenlinear_buckling.is_symmetric()is true for both matrices.- check_rtolfloat or None, optional
Maximum relative residual of an eigenpair, \(||K u + \lambda^2 M u||/(||K u|| + |\lambda^2| ||M u||)\). For a rigid-body mode, whose \(||K u|| + |\lambda^2| ||M u||\) is not larger than
linear_buckling.RIGID_BODY_RTOLtimes the matrix-norm scale \((||K||_F + |\lambda^2| ||M||_F) ||u||\), the residual is relative to this scale, seelinear_buckling._relative_residuals(). An eigenpair with a larger relative residual is also accepted when its normwise backward error \(||K u + \lambda^2 M u||/((||K||_F + |\lambda^2| ||M||_F) ||u||)\) is not larger thanlinear_buckling.BACKWARD_ERROR_RTOL, the machine precision, e.g. an eigenvalue close to zero of a model pre-stressed close to buckling, seelinear_buckling._backward_errors(). Any other larger residual of the sparse solver is a failed verification, see above. Forsparse_solver=False, a warning is issued.Noneskips the check.- max_dense_sizeint, optional
Maximum size of the dense problem solved as a last resort when the sparse solver failed, see above. Larger problems raise a
RuntimeErrorinstead, and0disables the dense fallback.- linear_solverstr, optional
'splu'(default) for the sparse factorizations of SuperLU, or'pardiso'for those of PARDISO, which requires the shared librarymkl_rtof Intel oneMKL, seestructsolve.pardiso, withsymmetric=True(orNonedetecting symmetric matrices) only; see the Notes.
- Returns:
- lambda2ndarray
Complex array with the eigenvalues \(\lambda^2 = -\omega_n^2\), real with
symmetric=True, sorted and filtered as described insort, otherwise in the order returned by the eigenvalue solver.- eigvecsndarray
The \(i^{th}\) eigenvector is
eigvecs[:, i], the eigenvector oflambda2[i], with the size of the original matrices. The sparse solver returns eigenvectors normalized with respect toM, the dense solver returns eigenvectors with unit Euclidean norm.
- Raises:
- RuntimeError
When the sparse solver failed and the dense fallback was not possible or failed too, listing the attempted solvers and their failures.
- Warns:
- .linear_buckling.DenseFallbackWarning
When the sparse solver failed and the dense solver was used.
Notes
The free-vibration eigenvalue problem is
\[(\boldsymbol{K} + \lambda^2 \boldsymbol{M}) \boldsymbol{u} = \boldsymbol{0}\]where \(\lambda^2 = -\omega_n^2\) and \(\omega_n\) is the natural frequency in rad/s. The sparse solvers solve \(\boldsymbol{K} \boldsymbol{u} = \omega_n^2 \boldsymbol{M} \boldsymbol{u}\) in shift-invert mode, which returns the \(\omega_n^2\) nearest the shift \(\sigma\) ([1], Chapter 3, Section 3.2, Eq. (3.2.2)). The negative shift is \(\sigma = -|\boldsymbol{y}^\top \boldsymbol{K} \boldsymbol{y} / \boldsymbol{y}^\top \boldsymbol{M} \boldsymbol{y}|\), the Rayleigh quotient of \(\boldsymbol{y} = \boldsymbol{K}^{-1} \boldsymbol{M} \boldsymbol{x}\) for a fixed random vector \(\boldsymbol{x}\), i.e. one step of inverse iteration towards the lowest \(\omega_n^2\), or \(\sigma = -1\) when
Kis singular or the solution is inaccurate. With all \(\omega_n^2 \ge 0\), the eigenvalues nearest a negative shift are the lowest ones.Verification. With
symmetric=True, the number of negative pivots of \(\boldsymbol{K} - s \boldsymbol{M}\), for \(s\) slightly lower than the highest \(\omega_n^2\) returned, is the number of eigenvalues below \(s\) (Sylvester’s law of inertia), see_check_freq().PARDISO. With
linear_solver='pardiso'and symmetric matrices,Kof the estimate of the shift, \(\boldsymbol{K} - \sigma \boldsymbol{M}\) of the shift-invert mode, passed toscipy.sparse.linalg.eigsh()asOPinv(also in the passes ofarpackutils.capped_eigsh()), and \(\boldsymbol{K} - s \boldsymbol{M}\) of the inertia count are factorized by PARDISO, the symmetric indefinite factorization ofstatic._factorize(), seelb(); ARPACK remains the eigenvalue solver. The count of negative eigenvalues of PARDISO is exact also when SuperLU would need a row interchange. As inlb(), SuperLU is used instead for a matrix whose factorization by PARDISO is inaccurate or, for the count, keeps perturbed pivots. The general solver of unsymmetric matrices,scipy.sparse.linalg.eigs(), and the dense solvers are unchanged.scipy.sparse.linalg.eigsh()uses ARPACK’s symmetric drivers, which return wrong eigenpairs when linked against Intel MKL 2024.2.0 to 2025.0.0 andncv > 32, seelb()andstructsolve.arpackutils, wherencvis capped accordingly.Non-conservative systems, e.g. under follower loads, may lose stability by flutter, which the static criterion of
lb()does not detect: withKthe tangent stiffness matrix at a load level, including the load stiffness, the eigenvalues \(\lambda^2\) of the general solvers are real and negative below the flutter load and become complex conjugate pairs above it, when two natural frequencies coalesce, a double root of the frequency equation. This is the dynamic method of [2] (Introduction, Sections 6 and 7, pp. 12-17), where \(\lambda\) is the characteristic exponent \(s = i\Omega\). A real positive \(\lambda^2\), i.e. a real positive \(\lambda\), indicates divergence ([2], p. 17).References
[1]Lehoucq, R.B., Sorensen, D.C., Yang, C., ARPACK Users’ Guide: Solution of Large-Scale Eigenvalue Problems with Implicitly Restarted Arnoldi Methods, SIAM, Philadelphia, 1998. https://doi.org/10.1137/1.9780898719628
See also Eigenvalue solvers for the solver policy.