Linear static analysis (structsolve.static)#
- structsolve.static(K, fext, silent=False)#
Linear static analysis
Solves the linear system
K u = fextusingsolve(). For linear andnon-linear static analyses based on callables that calculate the force vectors and stiffness matrices, see
Analysis.- Parameters:
- Ksparse_matrix
Stiffness matrix. Should include initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. It may be unsymmetric, e.g.
K0 + kCfollowerfor a follower load on a geometrically linear structure, whose load stiffness iskCfollower = -dF/dc.- fextarray-like
Vector of external loads.
- silentbool, optional
A boolean to tell whether the log messages should be printed.
- Returns:
- incrementslist
[1.], the load factor of the solution.- cslist
List with the solution vector.
- structsolve.solve(a, b, silent=False, **kwargs)#
Solve a linear system of equations removing null rows and columns
Wrapper for
scipy.sparse.linalg.spsolve(). The rows and columns ofawithout any non-zero term, typically the constrained degrees of freedom of a Ritz or finite element model, are removed before solving the linear system of equations. The corresponding values of the solutionxare zero.- Parameters:
- andarray or sparse matrix
A square matrix, converted to CSR form in the solution. It may be unsymmetric, e.g. with the load stiffness of follower loads, since
scipy.sparse.linalg.spsolve()uses an LU factorization. The degrees of freedom whose row and column are both null are removed.- bndarray
1-D array representing the right-hand side of the system of equations.
- silentbool, optional
A boolean to tell whether the log messages should be printed.
- kwargskeyword arguments, optional
Other arguments directly passed to
scipy.sparse.linalg.spsolve().
- Returns:
- xndarray
The solution of the system of equations, a 1-D array of size
a.shape[1]with the samedtypeasb.
Notes
With \(u\) the set of the degrees of freedom whose row or column of
ais not null, the reduced system \([a_{uu}]\boldsymbol{x}_u = \boldsymbol{b}_u\) is solved and \(x = 0\) at the other degrees of freedom. The terms ofbat the removed degrees of freedom are ignored:xsolves the full system only when they are null, otherwise the full system has no solution, since a null row and column makeasingular.
Factorizations of the tangent stiffness matrix#
- structsolve.static._factorize(kT, linear_solver='splu', constraints=None, cache=None)#
Factorization of the tangent stiffness matrix
Null rows and columns are removed, the corresponding values of the solution are zero, as in
solve(). The factorization is reused by the non-linear solvers while the tangent stiffness matrix is not updated.- Parameters:
- kTsparse matrix
Tangent stiffness matrix.
- linear_solverstr, optional
'splu'(default) for the sparse LU factorization of SuperLU, or'pardiso'for the symmetric indefinite factorization of PARDISO, which requires the shared librarymkl_rtof Intel oneMKL, seepardisoandLINEAR_SOLVERS.- constraintsarray-like, sparse matrix or None, optional
The matrix \(\boldsymbol{C}\) of the linear constraints \(\boldsymbol{C}^\top \boldsymbol{x} = \boldsymbol{0}\), of shape
(n, m)formconstraints, see the Notes.None(default) for none.- cache
_FactorizationCacheor None, optional Cache of the work that depends only on the sparsity pattern of
kT, reused by the next factorizations of a matrix of the same pattern, see the Notes.None(default) for none.
- Returns:
- solve_kTcallable
solve_kT(b, d=None)returns the solutionxofkT x = b, or of the system bordered by the constraints, whose values ared, of shape(m,), zeros whenNone, see the Notes; it has the attributes:linear_solver: the linear solver used,'splu'when'pardiso'fell back to it for an unsymmetric matrix;det_sign: the sign of the determinant of the reduced matrix,1or-1, on the space of the constraints when given;num_negative_eigvals: the number of negative eigenvalues of the reduced matrix with'pardiso', on the space of the constraints when given,Nonewith'splu';num_constraints: the numbermof constraints of the border;num_perturbed_pivots: the number of pivots perturbed by PARDISO,Nonewith'splu';smallest_eigvals, with'splu'only:smallest_eigvals(k, s=None)returns thekeigenvalues of smallest magnitude of the reduced matrix, scaled bydiag(s)on both sides when given, on the space of the constraints, by shift-invert with ARPACK and this factorization, see_smallest_eigvals().
- Raises:
- RuntimeError
When the matrix is singular, for
'splu', or when PARDISO fails.- ImportError
When
linear_solver='pardiso'and oneMKL is not found.- ValueError
For an invalid
linear_solver.
Notes
With
'splu', the reduced matrix is factorized once with SuperLU,scipy.sparse.linalg.splu()with its default options, i.e. a sparse LU factorization \(\boldsymbol{P}_r \boldsymbol{A} \boldsymbol{P}_c = \boldsymbol{L} \boldsymbol{U}\) with row and column permutations, valid for unsymmetric matrices. Each call ofsolve_kTis then only a forward and a backward substitution, which is why the factorization is reused while the tangent stiffness matrix is not updated, e.g. in the modified Newton-Raphson method and in the two solutions of the bordered system of the arc-length methods. \(\boldsymbol{L}\) having a unit diagonal, the sign of the determinant is the product of the signs of the diagonal of \(\boldsymbol{U}\) and of the two permutations; for a symmetric matrix it is \((-1)^{n_{neg}}\), with \(n_{neg}\) its number of negative eigenvalues, which LU does not give.With
'pardiso', the reduced matrix \(\boldsymbol{A}\) is scaled to a unit diagonal, \(\boldsymbol{A}_s = \boldsymbol{D} \boldsymbol{A} \boldsymbol{D}\), \(\boldsymbol{D} = \mathrm{diag}(|a_{ii}|^{-1/2})\), a null diagonal term being replaced by 1, and the upper triangle of \(\boldsymbol{A}_s\) is factorized by PARDISO as a real symmetric indefinite matrix (mtype=-2), \(\boldsymbol{L} \boldsymbol{D} \boldsymbol{L}^\top\) with Bunch-Kaufman pivoting. By Sylvester’s law of inertia, the number of negative pivots,iparm(23)of PARDISO, is the number of negative eigenvalues of \(\boldsymbol{A}_s\), hence of \(\boldsymbol{A}\), the congruence by \(\boldsymbol{D}\) preserving the inertia: zero on the stable parts of an equilibrium path, it changes at the limit points and at the bifurcation points crossed. PARDISO perturbs the pivots that are too small,iparm(14)of them, which makes the count uncertain when it is not zero. When the first factorization perturbed pivots, the matrix is factorized again with the parametersPARDISO_FALLBACK_IPARM,iparm(24) = 1, the two-level factorization algorithm, kept,solve_kT.pardiso_fallback = True, only when no pivot is perturbed and the relative residual of its solution of a random right-hand side, without refinement, is not larger thanPARDISO_ACCURACY_RTOL = 1e-6; otherwise the matrix is factorized by SuperLU, as'splu', with aRuntimeWarning, andnum_negative_eigvalsisNone: a factorization ofiparm(24) = 1without perturbed pivots had residuals up to 1e3 and a wrong inertia for some Ritz models of the tests (MKL 2025.0). Withcache, the next factorizations of the same pattern use the fallback directly, with the phase 12 and the same check, or SuperLU directly. The default factorizations without perturbed pivots are not checked, at no cost. The tangent stiffness matrices of a Ritz model of a cylinder (panels 0.15.0,cylshell_clpt_donnell, 8 x 8 terms, 114 degrees of freedom, a dense matrix) and dense random indefinite matrices of 114 and 200 degrees of freedom had 18 to 40 perturbed pivots with the default parameters (MKL 2026.1,iparm(10) = 8,iparm(11) = iparm(13) = 0,iparm(21) = 1,iparm(24) = 0), solutions of relative residual 0.4 to 1, recovered by the GMRES below, and a number of negative pivots short by one, e.g. 0 from the load factor 0.827 of the critical point, where a dense eigenvalue analysis has one negative eigenvalue, up to 0.903; neitheriparm(10) = 13or20, nor the scaling and the weighted matching,iparm(11) = iparm(13) = 1, noriparm(21) = 3changed it, andiparm(24) = 1gave no perturbed pivot, the counts of the dense eigenvalue analysis along the whole path, and residuals of1e-13. The tangent of the DOE09 cylinder below, sparse, had no perturbed pivot. The diagonal of the tangent of a model with derivatives of the displacements among its unknowns may span many orders of magnitude, which the scaling compensates. Every solution is checked against its relative residual \(\|\boldsymbol{A} \boldsymbol{x} - \boldsymbol{b}\|/\|\boldsymbol{b}\|\) and, when it is larger thanPARDISO_REFINE_TOL, improved by GMRES with the factorization as the preconditioner, to the relative tolerancePARDISO_GMRES_RTOL; aRuntimeWarningis issued when the residual remains larger thanPARDISO_WARN_TOL. These are the settings of the Riks analyses of a tow-steered cylinder for the DCSE website (2026), where the unsymmetric LU of PARDISO was wrong and its Cholesky factorization failed beyond the limit point. The symmetric factorization would be wrong for an unsymmetric matrix, e.g. with the load stiffness of a follower load:'splu'is then used, with aRuntimeWarning. Withconstraints, the bordered system\[\begin{split}\begin{bmatrix} \boldsymbol{0} & \boldsymbol{C}^\top \\ \boldsymbol{C} & \boldsymbol{K}_T \end{bmatrix} \begin{Bmatrix} \boldsymbol{\mu} \\ \boldsymbol{x} \end{Bmatrix} = \begin{Bmatrix} \boldsymbol{d} \\ \boldsymbol{b} \end{Bmatrix}\end{split}\]is factorized instead, the border first, such that no row of the upper triangle factorized by PARDISO is empty, and
solve_kTreturns \(\boldsymbol{x}\), which satisfies \(\boldsymbol{C}^\top \boldsymbol{x} = \boldsymbol{d}\), \(\boldsymbol{\mu}\) being the Lagrange multipliers, the reactions of the constraints, \(\boldsymbol{d} = \boldsymbol{0}\) unlessdis given, e.g. a prescribed displacement. The rows of \(\boldsymbol{C}\) of the null rows and columns ofkTare removed, and the constraints left without any non-zero term, satisfied with \(d_j = 0\), are dropped; a non-zero \(d_j\) of such a constraint raises aValueError, the degrees of freedom of the null rows and columns being zero. The bordered matrix is indefinite even when \(\boldsymbol{K}_T\) is positive definite on the space of the constraints: for \(\boldsymbol{C}\) of full rank its inertia is that of \(\boldsymbol{Z}^\top \boldsymbol{K}_T \boldsymbol{Z}\) plus \(m\) positive and \(m\) negative eigenvalues, \(\boldsymbol{Z}\) a basis of the null space of \(\boldsymbol{C}^\top\) (Gould, N.I.M., On practical conditions for the existence and uniqueness of solutions to the general equality quadratic programming problem, Mathematical Programming, 32, 90-99, 1985), hencenum_negative_eigvalsis the number of negative pivots minus \(m\), anddet_signis multiplied by \((-1)^m\). This is the border of the inertia relief of the Riks analyses of a tow-steered cylinder for the DCSE website (2026), with a single constraint.PARDISO is called through
PardisoSolver, whose memory is freed whensolve_kTis deleted.With
cache, created byAnalysis.static()for each non-linear analysis, along which the pattern of the tangent stiffness matrix usually does not change, the work that depends only on the pattern is done once per pattern: the indices of the reduced and bordered matrix, of its CSC form, of the transposed terms of the symmetry check, of its diagonal and of the scaled upper triangle, from which each factorization only gathers the values ofkT; and the analysis (reordering and symbolic factorization) of PARDISO, its phase 11, the next factorizations being its phase 22 instead of 12 with a solver that keeps the analysis of the pattern; up toCACHE_MAX_PARDISO_SOLVERSsuch solvers are kept, since the factorizations of the last converged state and of the current iteration coexist. The pattern is the shape,indptrandindicesofkTin CSR form, compared at every call, the degrees of freedom whose row or column is not null, which depend on the values, since explicit zeros do not count, computed at every call, andconstraints, compared with its values; any change rebuilds the cache. The values enter only through the gathered terms, and the symmetry check, the scaling and the null rows and columns are evaluated at every call, such that the factorization is bitwise the one without the cache, verified by the tests, also the inertia and the perturbed pivots of PARDISO (withMKL_NUM_THREADS=1; the analysis of PARDISO depends only on the pattern, with its defaultiparm(11) = iparm(13) = 0for symmetric indefinite matrices). A matrix that is notfloat64or whose CSR form has duplicated or unsorted terms is factorized without the cache. On a symmetric matrix of 57000 degrees of freedom with 4.5 million terms, the factorization took 1.65 s without and 0.40 s with the cache with'pardiso', with or without one constraint, and 1.1 s with'splu', whose preprocessing went from 0.11 s to 0.05 s, SuperLU computing its ordering at every factorization.
- structsolve.static._smallest_eigvals(lu, m, k, s=None)#
The
keigenvalues of smallest magnitude of the matrix of the SuperLU factorizationlu, on the space of itsmconstraintsThe matrix is the reduced matrix \(\boldsymbol{K}\) of
_factorize(), bordered first bymconstraints \(\boldsymbol{C}\). Shift-invert at \(\sigma = 0\) with ARPACK,scipy.sparse.linalg.eigs(), on the operator \(\boldsymbol{T} \boldsymbol{b} = \boldsymbol{x}\), the solution of the bordered system \(\boldsymbol{K} \boldsymbol{x} + \boldsymbol{C} \boldsymbol{\mu} = \boldsymbol{b}\), \(\boldsymbol{C}^\top \boldsymbol{x} = \boldsymbol{0}\), by the forward and backward substitutions oflu, which is not factorized again: an eigenvalue \(\nu \ne 0\) of \(\boldsymbol{T}\) has its eigenvector \(\boldsymbol{b}\) in the null space of \(\boldsymbol{C}^\top\), and \(\boldsymbol{P} \boldsymbol{K} \boldsymbol{b} = \boldsymbol{b}/\nu\), \(\boldsymbol{P}\) the orthogonal projection on that space, i.e. \(\lambda = 1/\nu\) is an eigenvalue of \(\boldsymbol{Z}^\top \boldsymbol{K} \boldsymbol{Z}\), \(\boldsymbol{Z}\) an orthonormal basis of the null space of \(\boldsymbol{C}^\top\); the range of \(\boldsymbol{C}\), of \(\nu = 0\), is not among the largest \(|\nu|\). Withklarger than the size minus 2, the limit of ARPACK, all the eigenvalues are computed withnumpy.linalg.eigvals()from \(\boldsymbol{T}\) built column by column.With the scaling
s, of the reduced degrees of freedom, the eigenvalues are those of \(\boldsymbol{S} \boldsymbol{K} \boldsymbol{S}\), \(\boldsymbol{S} = \mathrm{diag}(s)\), with the constraints \(\boldsymbol{S} \boldsymbol{C}\), from the operator \(\boldsymbol{S}^{-1} \boldsymbol{T} \boldsymbol{S}^{-1}\): those of \(\boldsymbol{K} \boldsymbol{v} = \lambda \boldsymbol{S}^{-2} \boldsymbol{v}\), with the positive diagonal reference matrix \(\boldsymbol{S}^{-2}\), seenewton_raphson._eigvals_inertia().smallest_eigvals(k, s)of_factorize()takessof all the degrees of freedom.- Returns:
- lamndarray or None
The eigenvalues, complex, sorted by increasing magnitude,
Nonewhen ARPACK did not converge.
- structsolve.static._pardiso_factorize_fallback(A, iparm)#
Factorization of phase 12 of
Aby a newPardisoSolverwith the parametersiparm(the defaults filled by a previous factorization),iparm(1) = 1, and those ofPARDISO_FALLBACK_IPARM;Nonewhen it fails
- structsolve.static.PARDISO_FALLBACK_IPARM = {24: 1}#
'pardiso': parameters,{i: iparm(i)}, of the second factorization of a matrix whose first factorization, with the default parameters, perturbed pivots:iparm(24) = 1, the two-level factorization algorithm instead of the classic one, see_factorize()