pyserep.utils
pyserep.utils — timing, linear algebra, and sparse matrix utilities.
- class pyserep.utils.Timer(label: str = '', verbose: bool = True)[source]
Bases:
objectContext-manager wall-clock timer.
- pyserep.utils.ansys_dof(node: int, direction: int) int[source]
Convert Ansys node number + direction to a 0-based DOF index.
DOF_index = (node_number − 1) × 3 + direction
- Parameters:
node (int — 1-based Ansys node number)
direction (int — 0=UX, 1=UY, 2=UZ)
- Return type:
int — 0-based DOF index
- pyserep.utils.apply_bcs(K: spmatrix, M: spmatrix, fixed_dofs: List[int], penalty: float = 1000000000000000.0) Tuple[csc_matrix, csc_matrix][source]
Apply fixed-DOF boundary conditions via the penalty method.
Sets K[dof, dof] += penalty and M[dof, dof] = 1 for each fixed DOF. This is numerically equivalent to removing the rows/columns but preserves the matrix dimensions (convenient for DOF indexing).
- Parameters:
- Returns:
K_bc, M_bc
- Return type:
- pyserep.utils.build_dof_map(master_dofs: ndarray, force_dofs: List[int], output_dofs: List[int]) Tuple[List[int], List[int]][source]
Map global force/output DOF indices → local indices within master_dofs.
- pyserep.utils.condition_number_estimate(A: ndarray, method: str = 'exact') float[source]
Estimate the 2-norm condition number of a dense matrix A.
- Parameters:
A (np.ndarray, shape (m, n))
method (str) –
"exact"— full SVD (always accurate, O(mn²))"fast"— power iteration on AᵀA (cheaper for large m)
- Return type:
float — κ(A) = σ_max / σ_min
- pyserep.utils.diagonal_scaling(K: spmatrix, M: spmatrix) Tuple[csc_matrix, csc_matrix, ndarray][source]
Scale (K, M) by the diagonal of M to improve eigensolver conditioning.
Transformation: K̃ = D⁻½ K D⁻½, M̃ = D⁻½ M D⁻½
where D = diag(M). This converts the generalised problem to a standard one when M is diagonal (lumped mass), and improves conditioning for consistent mass matrices.
- Parameters:
K (scipy.sparse matrices)
M (scipy.sparse matrices)
- Returns:
K_scaled, M_scaled (scipy.sparse.csc_matrix)
D_inv_sqrt (np.ndarray, shape (N,) — scaling vector for back-transformation)
- pyserep.utils.dof_to_ansys(dof: int) Tuple[int, int][source]
Convert a 0-based DOF index to (node_number, direction).
Inverse of
ansys_dof().- Return type:
(node_number, direction) — 1-based node, direction in {0,1,2}
- pyserep.utils.force_positive_definite(A: ndarray, shift_factor: float = 1e-08, max_iter: int = 50) Tuple[ndarray, float][source]
Make A symmetric positive definite by adding a small multiple of the identity until Cholesky succeeds.
Uses the modified Cholesky approach of Gill, Murray & Wright (1981).
- Parameters:
- Returns:
A_pd (np.ndarray — positive-definite version of A)
shift (float — total shift applied (0 if A was already PD))
Examples
>>> Ka_pd, shift = force_positive_definite(Ka) >>> np.linalg.cholesky(Ka_pd) # succeeds
- pyserep.utils.is_diagonal(mat: spmatrix, tol: float = 1e-12) bool[source]
Return True if mat is effectively diagonal (lumped mass).
- pyserep.utils.mass_normalise(phi: ndarray, M: spmatrix) ndarray[source]
Normalise mode shapes so that Φᵢᵀ M Φᵢ = 1 for every column i.
- Parameters:
phi (np.ndarray, shape (N, m))
M (scipy.sparse matrix, shape (N, N))
- Return type:
np.ndarray, shape (N, m) — mass-normalised phi
- pyserep.utils.matrix_stats(K: spmatrix, M: spmatrix, label: str = '') str[source]
Return a formatted statistics string for a (K, M) pair.
- pyserep.utils.memory_mb(mat: spmatrix) float[source]
Return memory usage of a sparse matrix in MB (data + indices + indptr).
- pyserep.utils.modal_residues(phi: ndarray, force_dofs: list, output_dofs: list, selected_modes: ndarray) ndarray[source]
Compute modal residues Rᵢ = φᵢ(f) · φᵢ(o) for each mode and DOF pair.
- pyserep.utils.modal_strain_energy(phi: ndarray, K: spmatrix, selected_modes: ndarray) ndarray[source]
Compute the modal strain energy (MSE) for each selected mode.
MSE_i = φᵢᵀ K φᵢ (= ωᵢ² for mass-normalised modes)
- Parameters:
phi (np.ndarray, shape (N, n_all_modes))
K (sparse stiffness matrix)
selected_modes (np.ndarray of int)
- Return type:
np.ndarray, shape (len(selected_modes),) — modal strain energies
- pyserep.utils.rank_revealing_qr(A: ndarray, tol: float | None = None) Tuple[ndarray, ndarray, ndarray, int][source]
Rank-revealing QR factorisation with column pivoting.
Computes: A P = Q R where P is a permutation.
- Parameters:
- Returns:
Q (np.ndarray, shape (m, m))
R (np.ndarray, shape (m, n))
perm (np.ndarray of int, shape (n,) — column permutation)
rank (int — estimated numerical rank)
Examples
>>> Q, R, perm, r = rank_revealing_qr(phi_a) >>> perm[:r] # top-r most informative DOFs
- pyserep.utils.reorder_rcm(K: spmatrix, M: spmatrix) Tuple[csc_matrix, csc_matrix, ndarray][source]
Apply Reverse Cuthill-McKee (RCM) reordering to reduce bandwidth.
Reduces the bandwidth of K (and correspondingly M), which can speed up sparse direct solvers used during FRF computation.
- Parameters:
K (sparse matrices (square, symmetric))
M (sparse matrices (square, symmetric))
- Returns:
K_rcm, M_rcm (scipy.sparse.csc_matrix — reordered matrices)
perm (np.ndarray of int — permutation vector (K_rcm = K[perm, :][:, perm]))
Notes
The same permutation must be applied to DOF index arrays (master_dofs, force_dofs, etc.) when using the reordered matrices. Use
perm_inv = np.argsort(perm)to convert global DOF indices back.
- pyserep.utils.safe_pinv(A: ndarray, rcond: float | None = None, verbose: bool = False) ndarray[source]
Compute the Moore–Penrose pseudoinverse with automatic rank truncation.
Drops singular values below
rcond * σ_maxto avoid numerical blow-up from near-zero singular values.
- pyserep.utils.sparse_submatrix(A: spmatrix, row_idx: ndarray, col_idx: ndarray | None = None) csc_matrix[source]
Extract a submatrix A[row_idx, :][:, col_idx] efficiently.
- Parameters:
- Return type:
- pyserep.utils.sparsity(mat: spmatrix) float[source]
Return the fraction of structural zeros (higher = sparser).