Linear buckling analysis (structsolve.linear_buckling)#
- structsolve.lb(K, KG, tol=0, sparse_solver=True, silent=False, num_eigvalues=25, num_eigvalues_print=5, skip_null_cols=False, max_dense_size=2000, check_rtol=0.001, symmetric=None, linear_solver='splu')#
Linear buckling analysis
Calculates the load multipliers
lambdaand the buckling modesuof the linear buckling problem ofKandKG, i.e. the eigenpairs with(K + lambda*KG) @ u = 0, wherelambdais the load multiplier of the load state that generatedKG. It can also be used for more general eigenvalue analyses, e.g. ifKis the tangent stiffness matrix of a given load state. The null rows and columns ofKare removed from both matrices before solving the eigenvalue problem, unlessskip_null_cols=True.Solver policy. With
sparse_solver=Truethe sparse solvers run first for every problem size, in the order given below, and each result must pass the verification: the relative residual of each eigenpair must not be larger thancheck_rtoland, for symmetric matrices with a positive definiteK, no positive load multiplier below the highest one returned, and no negative one closer to zero than the returned ones, may be missing, see_check_both_signs(). Only when all of them failed (verification, ARPACK error or no convergence, singular factorization, no positive real load multiplier…) a dense solver is used, if the dense problem has at mostmax_dense_sizedofs, with aDenseFallbackWarningthat gives the reasons of the failures. Its result is verified as well. ARuntimeErrorlisting every attempted solver is raised when the problem is too large for the dense fallback, or when the dense solution also failed.Symmetric matrices. The sparse solvers are:
scipy.sparse.linalg.eigsh()in Cayley mode, with the shift estimated from the matrices by_estimate_sigma();the same with a 10 times larger shift.
Each one computes the lowest positive load multipliers and, when fewer than
num_eigvaluesexist, the negative ones closest to zero, i.e. the critical load multipliers of the reversed load, with-KG, see_eigsh_both_signs(). A reference load without any positive load multiplier, e.g. a tensile load, is solved by the sparse solvers too. The dense fallback condenses out the dofs whereKGhas null rows and solves the condensed problem withscipy.linalg.eigh(), see_eigh_condensed().Unsymmetric matrices, e.g.
KGwith the load stiffness of a follower pressure, may have complex load multipliers. The sparse solver is a search of shifts along the positive real axis withscipy.sparse.linalg.eigs(), see_eigs_shift_search(), which finds the lowest positive real load multiplier. The returned eigenpairs are thenum_eigvaluesload multipliers nearest the last shift of the search, which is zero unless the multipliers of smallest modulus did not include a positive real one, not necessarily the load multipliers of smallest modulus. The dense fallback,_eig_condensed(), keeps the dofs where either the row or the column ofKGis not null, and returns thenum_eigvaluesfirst load multipliers in the order described in Returns; when none of them is positive and real, they are returned with a warning. Eigenvalues whose imaginary part is below1e-8of their modulus are returned as real, with real eigenvectors. The arrays are real when the returned eigenpairs are real, even if other eigenvalues of the solver are complex.Intel MKL. When SciPy is linked against Intel MKL 2024.2.0 to 2025.0.0,
ncvofscipy.sparse.linalg.eigsh()is capped at 32 and more than 15 eigenpairs are computed in several passes, seestructsolve.arpackutils, where the cap can be overridden, e.g. with the environment variableSTRUCTSOLVE_ARPACK_MAX_NCV=0to lift it with MKL 2025.0.1 or newer. The dense solvers of unsymmetric matrices callscipy.linalg.eig()with complex matrices.- Parameters:
- Ksparse_matrix
Stiffness matrix. Should include all constant terms of the initial stress stiffness matrix, aerodynamic matrix and so forth when applicable.
- KGsparse_matrix
Initial stress stiffness matrix that multiplies the load multiplier \(\lambda\) of the eigenvalue problem.
- tolfloat, optional
A float tolerance passed to
scipy.sparse.linalg.eigsh()andscipy.sparse.linalg.eigs().- sparse_solverbool, optional
With
True, the default, the sparse solvers always run first, whatever the size of the problem, and a dense solver is only used as a last resort, see above.num_eigvaluesload multipliers are returned. WithFalse, the full problem is explicitly solved with a dense solver, without trying the sparse solvers:scipy.linalg.eigh(), which requires a positive definiteK, orscipy.linalg.eig()for unsymmetric matrices, returning all the load multipliers. It is a reference for validations and for the callers that need all of them.- silentbool, optional
A boolean to tell whether the log messages should be printed.
- num_eigvaluesint, optional
Number of load multipliers calculated with the sparse solver, and number of returned eigenvectors. Fewer are returned by the sparse solver of symmetric matrices when fewer finite load multipliers exist, the infinite ones, e.g. of the null rows of
KG, being discarded.- 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 K is known to be non-singular.
- max_dense_sizeint, optional
Maximum size of the dense problem solved as a last resort, when all the sparse solvers failed, i.e. the number of non-null rows of
KG, or of non-null rows or columns for unsymmetric matrices, see above. Larger problems raise aRuntimeErrorinstead, and0disables the dense fallback. Until version 0.5.3, it was the size below which the dense solver was tried first.- check_rtolfloat, optional
Maximum relative residual
||K u + lambda KG u|| / (||K u|| + |lambda| ||KG u||)of the eigenpairs of the sparse solver, see above and_relative_residuals().- symmetricbool or None, optional
Whether
KandKGare symmetric.Nonechecks it withis_symmetric(),Trueskips the check and uses the solvers of symmetric matrices,Falseforces the solvers of unsymmetric matrices, required e.g. whenKGincludes the load stiffness of follower loads, see above.- 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, in the sparse solvers of symmetric matrices only; see the Notes.
- Returns:
- eigvalsndarray
The load multipliers \(\lambda\), calculated as
-1/eigvalfrom the eigenvalueseigvalofKG u = eigval K u. The positive load multipliers come first in increasing order, followed by the negative ones in order of increasing modulus, i.e. the critical load multipliers of the reversed load first, for both solvers. For unsymmetric matrices the array is complex when some eigenvalues are complex, which come after the real ones by increasing modulus. The load multipliers of the nulleigval,|eigval|not larger thanNULL_MU_RTOLtimes the largest|eigval|, infinite up to the round-off, come last; the dense solvers also take as null theeigvalnot determined by the round-off, seelinear_buckling._null_mu_pencil, returned as-inf.- eigvecsndarray
The \(i^{th}\) eigenvector is
eigvecs[:, i], with the size of the original matrices. Onlynum_eigvalueseigenvectors are returned.
- Raises:
- RuntimeError
When no eigenvalue solver passed the verification, with the list of the attempted solvers and their failures.
- Warns:
- DenseFallbackWarning
When the sparse solvers failed and the dense solver was used.
- RuntimeWarning
For unsymmetric matrices, when the dense fallback found no positive real load multiplier.
Notes
The eigenvalue problem is
\[(\boldsymbol{K} + \lambda \boldsymbol{K}_G) \boldsymbol{u} = \boldsymbol{0}\]where \(\lambda\) is the load multiplier of the load state that generated \(\boldsymbol{K}_G\). It is solved as \(\boldsymbol{K}_G \boldsymbol{u} = \mu \boldsymbol{K} \boldsymbol{u}\), with \(\lambda = -1/\mu\); the null eigenvalues \(\mu\), e.g. of the dofs where \(\boldsymbol{K}_G\) is null, give infinite load multipliers.
Solver policy. The dense fallback keeps structsolve robust where ARPACK is unreliable, normal runs never pay for a dense solution.
Symmetric matrices. The shift of the Cayley mode is estimated by power iterations on \(\boldsymbol{K}^{-1} \boldsymbol{K}_G\), see
_estimate_sigma()and_eigsh_cayley(). The dense fallback condenses out the dofs whereKGhas null rows, typically the in-plane dofs, with a sparse factorization ofK, see_eigh_condensed(). The eigenpairs are verified as follows:the relative residual \(||K u + \lambda K_G u|| / (||K u|| + |\lambda| ||K_G u||)\) of each eigenpair must not be larger than
check_rtol, see_relative_residuals();when
Kis positive definite, no load multiplier below the highest positive one returned may be missing: the number of negative pivots of \(\boldsymbol{K} + s \boldsymbol{K}_G\), for \(s\) slightly below that multiplier, is the number of load multipliers in \((0, s)\) (Sylvester’s law of inertia). The factorization is done with SuperLU, without row interchanges, or with PARDISO, see below. When a row interchange was needed and the count is unknown, \(\boldsymbol{K} + s \boldsymbol{K}_G\) must be positive definite for \(s\) slightly below the lowest positive load multiplier. See_check_eigenpairs();the same for the negative load multipliers with \(-\boldsymbol{K}_G\), i.e. the positive load multipliers of the reversed load, see
_check_both_signs().
The Cayley mode selects all the negative \(\mu\), i.e. the positive load multipliers, before the null and the positive \(\mu\). The load multipliers of each sign are first counted with the inertia of \(\boldsymbol{K} + s \boldsymbol{K}_G\), for \(|s|\) equal to
INERTIA_COUNT_FACTORtimes the lowest modulus that a load multiplier may have, and at most as many are requested, since ARPACK may not converge when it must return eigenvalues of the cluster of the null \(\mu\). When fewer thannum_eigvaluespositive load multipliers exist, the Cayley mode with \(-\boldsymbol{K}_G\) gives the negative load multipliers closest to zero, see_eigsh_both_signs().PARDISO. With
linear_solver='pardiso', the factorizations of the sparse solvers of symmetric matrices are done by PARDISO, throughstatic._factorize(): the symmetric indefinite factorization \(\boldsymbol{L} \boldsymbol{D} \boldsymbol{L}^\top\) of the matrix scaled to a unit diagonal, with its fallback on perturbed pivots. ARPACK remains the eigenvalue solver: the operator \((\boldsymbol{K}_G - \sigma \boldsymbol{K})^{-1}\) of the Cayley mode, also of the passes ofarpackutils.capped_eigsh(), is passed toscipy.sparse.linalg.eigsh()asOPinv, each solution refined by GMRES when its residual is too large, seearpackutils.pardiso_solve();Kof the power iterations of_estimate_mu_max()and the matrices \(\boldsymbol{K} + s \boldsymbol{K}_G\) of the inertia counts are factorized by PARDISO too. The number of negative pivots is then the number of negative eigenvalues given by PARDISO, exact also when SuperLU would need a row interchange, for which its count is unknown. A factorization of PARDISO is used only when it is accurate: the relative residual of its solution for a random right-hand side must not be larger thanarpackutils.PARDISO_ACCURACY_RTOL, and no pivot may remain perturbed for the counts; otherwise SuperLU is used for that matrix, with aRuntimeWarningfor the operator of ARPACK, seearpackutils.pardiso_solve()and_negative_pivots(). The symmetric indefinite factorization of PARDISO (MKL 2025.0, default parameters,iparm(2) = 2,iparm(10) = 8) of the Ritz models of the tests, e.g.cylinder_5panels(1140 dofs) andplate_ssss_Nxx(300 dofs), perturbed 5 to 80 pivots and gave residuals of 1 to 50, also for a positive definiteK, and its fallbackiparm(24) = 1ofstatic._factorize()reported no perturbed pivot with residuals of 1 to 2e7 and a wrong inertia; for these models'pardiso'thus falls back to SuperLU. The solvers of unsymmetric matrices and the dense fallbacks, also the sparse factorization ofKof_eigh_condensed(), keep SuperLU and LAPACK.Unsymmetric matrices, e.g.
KGwith the load stiffness of a follower pressure that is not conservative, may have complex eigenvalues. The search of shifts of_eigs_shift_search()finds the lowest positive real load multiplier even when many negative or complex multipliers have a smaller modulus, verifies the residuals, and checks the parity of the number of real multipliers below the critical one. The dofs kept by the dense fallback, where either the row or the column ofKGis not null, are for follower loads almost all of them. When no returned load multiplier is positive and real, no divergence load exists, e.g. for a system that only loses stability by flutter, seefreq(). The inertia check requires symmetric matrices and is skipped.Intel MKL. ARPACK, used by
scipy.sparse.linalg.eigsh(), returns wrong eigenpairs at random, without any error, or raisesArpackError -8when linked against Intel MKL 2024.2.0 to 2025.0.0, e.g. in some Anaconda builds of SciPy: thedsteqrroutine of these MKL versions returns wrong eigenvectors for matrices larger than 32 x 32, which ARPACK uses with the sizencv. When such a LAPACK is detected,ncvis capped at 32 and more than 15 eigenpairs are computed in several passes, combined with a Rayleigh-Ritz projection, seestructsolve.arpackutils. The non-symmetric drivers ofscipy.sparse.linalg.eigs()are not affected.With Intel MKL 2025.0.0, the real LAPACK drivers
dgeevanddggevofscipy.linalg.eig()crash the Python process for some matrices when computing the eigenvectors, with any number of threads. The dense solvers of unsymmetric matrices therefore callscipy.linalg.eig()with complex matrices, i.e.zgeevandzggev, which are not affected.
- structsolve.linear_buckling.is_symmetric(A, rtol=1e-10)#
Tell whether
||A - A^T|| <= rtol ||A||, in the Frobenius normA cheap check, of the order of the number of non-zero entries of
A, used bylb()to select the solvers of symmetric or unsymmetric matrices.- Parameters:
- Aarray or sparse matrix
Square matrix, converted to CSR format.
- rtolfloat, optional
Relative tolerance, dimensionless. Default
1e-10.
- Returns:
- symmetricbool
Truewhen the Frobenius norm ofA - A^Tis not larger thanrtoltimes the Frobenius norm ofA.
See also
structsolve.sparseutils.is_symmetricentry-wise check.
- class structsolve.DenseFallbackWarning#
Issued by
lb()andfreq()when the sparse eigenvalue solvers failed and the dense solver was used as a last resortA subclass of
RuntimeWarning, issued withwarnings.warn(), whose message gives the reasons of the failures of the sparse solvers. It can be turned into an error withwarnings.simplefilter('error', DenseFallbackWarning).
See also Eigenvalue solvers for the solver policy.