def freq(K, M, tol=0, sparse_solver=True, silent=False, sort=True, reduced_dof=False, num_eigvalues=25, num_eigvalues_print=5): """Frequency Analysis Parameters ---------- K : sparse_matrix Stiffness matrix. Should include initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. M : sparse_matrix Mass matrix. tol : float, optional A tolerance value passed to ``scipy.sparse.linalg.eigs``. sparse_solver : bool, optional Tells if solver :func:`scipy.linalg.eig` or :func:`scipy.sparse.linalg.eigs` should be used. .. note:: It is recommended ``sparse_solver=False``, because it was verified that the sparse solver becomes unstable for some cases, though the sparse solver is faster. silent : bool, optional A boolean to tell whether the log messages should be printed. sort : bool, optional Sort the output eigenvalues and eigenmodes. reduced_dof : bool, optional Considers only the contributions of `v` and `w` to the stiffness matrix and accelerates the run. Only effective when ``sparse_solver=False``. num_eigvalues : int, optional Number of calculated eigenvalues. num_eigvalues_print : int, optional Number of eigenvalues to print. Returns ------- The extracted eigenvalues are stored in the ``eigvals`` parameter and the `i^{th}` eigenvector in the ``eigvecs[:, i-1]`` parameter. """ msg('Running frequency analysis...', silent=silent) msg('Eigenvalue solver... ', level=2, silent=silent) k = min(num_eigvalues, M.shape[0]-2) if sparse_solver: msg('eigs() solver...', level=3, silent=silent) sizebkp = M.shape[0] K, M, used_cols = remove_null_cols(K, M, silent=silent, level=3) #NOTE Looking for better performance with symmetric matrices, I tried # using compmech.sparse.is_symmetric and eigsh, but it seems not # to improve speed (I did not try passing only half of the sparse # matrices to the solver) eigvals, peigvecs = eigs(A=K, k=k, which='LM', M=M, tol=tol, sigma=-1.) eigvecs = np.zeros((sizebkp, num_eigvalues), dtype=peigvecs.dtype) eigvecs[used_cols, :] = peigvecs eigvals = np.sqrt(eigvals) # omega^2 to omega, in rad/s else: msg('eig() solver...', level=3, silent=silent) M = M.toarray() K = K.toarray() sizebkp = M.shape[0] col_sum = M.sum(axis=0) check = col_sum != 0 used_cols = np.arange(M.shape[0])[check] M = M[:, check][check, :] K = K[:, check][check, :] if reduced_dof: i = np.arange(M.shape[0]) take = np.column_stack((i[1::3], i[2::3])).flatten() M = M[:, take][take, :] K = K[:, take][take, :] #TODO did not try using eigh when input is symmetric to see if there # will be speed improvements eigvals, peigvecs = eig(a=-M, b=K) eigvecs = np.zeros((sizebkp, K.shape[0]), dtype=peigvecs.dtype) eigvecs[check, :] = peigvecs eigvals = np.sqrt(-1./eigvals) # -1/omega^2 to omega, in rad/s eigvals = eigvals msg('finished!', level=3, silent=silent) if sort: sort_ind = np.lexsort((np.round(eigvals.imag, 1), np.round(eigvals.real, 1))) eigvals = eigvals[sort_ind] eigvecs = eigvecs[:, sort_ind] higher_zero = eigvals.real > 1e-6 eigvals = eigvals[higher_zero] eigvecs = eigvecs[:, higher_zero] if not sparse_solver and reduced_dof: new_eigvecs = np.zeros((3*eigvecs.shape[0]//2, eigvecs.shape[1]), dtype=eigvecs.dtype) new_eigvecs[take, :] = eigvecs eigvecs = new_eigvecs msg('finished!', level=2, silent=silent) msg('first {0} eigenvalues:'.format(num_eigvalues_print), level=1, silent=silent) for eigval in eigvals[:num_eigvalues_print]: msg('{0} rad/s'.format(eigval), level=2, silent=silent) return eigvals, eigvecs
msg('eigs() solver...', level=3) eigvals, peigvecs = eigs(A=A, k=self.num_eigvalues, which='SM', M=M, tol=tol, sigma=1.) msg('finished!', level=3) eigvecs = np.zeros((sizebkp, self.num_eigvalues), dtype=DOUBLE) eigvecs[used_cols, :] = peigvecs # Un-normalizing eigvals eigvals *= Amin else: from scipy.linalg import eigh size22 = A.shape[0] M, A, used_cols = remove_null_cols(M, A) M = M.toarray() A = A.toarray() msg('eigh() solver...', level=3) eigvals, peigvecs = eigh(a=A, b=M) msg('finished!', level=3) eigvecs = np.zeros((size22, self.num_eigvalues), dtype=DOUBLE) eigvecs[used_cols, :] = peigvecs[:, :self.num_eigvalues] eigvals = -1./eigvals self.eigvals = eigvals self.eigvecs = eigvecs msg('finished!', level=2)
def lb(self, tol=0, combined_load_case=None, sparse_solver=True, calc_kA=False): """Performs a linear buckling analysis The following parameters of the ``AeroPistonPlate`` object will affect the linear buckling analysis: ======================= ===================================== parameter description ======================= ===================================== ``num_eigenvalues`` Number of eigenvalues to be extracted ``num_eigvalues_print`` Number of eigenvalues to print after the analysis is completed ======================= ===================================== Parameters ---------- combined_load_case : int, optional It tells whether the linear buckling analysis must be computed considering combined load cases, each value will tell the algorithm to rearrange the linear matrices in a different way. The valid values are ``1``, or ``2``, where: - ``1`` : find the critical Fx for a fixed Fxy - ``2`` : find the critical Fx for a fixed Fy - ``3`` : find the critical Fy for a fixed Fyx - ``4`` : find the critical Fy for a fixed Fx sparse_solver : bool, optional Tells if solver :func:`scipy.linalg.eigh` or :func:`scipy.sparse.linalg.eigs` should be used. Notes ----- The extracted eigenvalues are stored in the ``eigvals`` parameter of the ``AeroPistonPlate`` object and the `i^{th}` eigenvector in the ``eigvecs[:, i-1]`` parameter. """ if not modelDB.db[self.model]['linear buckling']: msg('________________________________________________') msg('') warn('Model {} cannot be used in linear buckling analysis!'. format(self.model)) msg('________________________________________________') msg('Running linear buckling analysis...') self.calc_linear_matrices(combined_load_case=combined_load_case, calc_kM=False, calc_kA=calc_kA) msg('Eigenvalue solver... ', level=2) if calc_kA: kA = self.kA else: kA = self.k0*0 if combined_load_case is None: M = self.k0 + kA A = self.kG0 elif combined_load_case == 1: M = self.k0 - kA + self.kG0_Fxy A = self.kG0_Fx elif combined_load_case == 2: M = self.k0 - kA + self.kG0_Fy A = self.kG0_Fx elif combined_load_case == 3: M = self.k0 - kA + self.kG0_Fyx A = self.kG0_Fy elif combined_load_case == 4: M = self.k0 - kA + self.kG0_Fx A = self.kG0_Fy Amin = abs(A.min()) # normalizing A to improve numerical stability A /= Amin if sparse_solver: try: msg('eigs() solver...', level=3) eigvals, eigvecs = eigs(A=A, k=self.num_eigvalues, which='SM', M=M, tol=tol, sigma=1.) msg('finished!', level=3) except Exception, e: warn(str(e), level=4) msg('aborted!', level=3) sizebkp = A.shape[0] M, A, used_cols = remove_null_cols(M, A) msg('eigs() solver...', level=3) eigvals, peigvecs = eigs(A=A, k=self.num_eigvalues, which='SM', M=M, tol=tol, sigma=1.) msg('finished!', level=3) eigvecs = np.zeros((sizebkp, self.num_eigvalues), dtype=DOUBLE) eigvecs[used_cols, :] = peigvecs # Un-normalizing eigvals eigvals *= Amin
def lb(K, KG, tol=0, sparse_solver=True, silent=False, num_eigvalues=25, num_eigvalues_print=5): """Linear Buckling Analysis It can also be used for more general eigenvalue analyzes if `K` is the tangent stiffness matrix of a given load state. Parameters ---------- K : sparse_matrix Stiffness matrix. Should include all constant terms of the initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. KG : sparse_matrix Initial stress stiffness matrix that multiplies the load multiplcator `\lambda` of the eigenvalue problem. tol : float, optional A float tolerance passsed to the eigenvalue solver. sparse_solver : bool, optional Tells if solver :func:`scipy.linalg.eigh` or :func:`scipy.sparse.linalg.eigsh` should be used. silent : bool, optional A boolean to tell whether the log messages should be printed. num_eigvalues : int, optional Number of calculated eigenvalues. num_eigvalues_print : int, optional Number of eigenvalues to print. Notes ----- The extracted eigenvalues are stored in the ``eigvals`` parameter of the ``Panel`` object and the `i^{th}` eigenvector in the ``eigvecs[:, i-1]`` parameter. """ msg('Running linear buckling analysis...', silent=silent) msg('Eigenvalue solver... ', level=2, silent=silent) k = min(num_eigvalues, KG.shape[0]-2) if sparse_solver: mode = 'cayley' try: msg('eigsh() solver...', level=3, silent=silent) eigvals, eigvecs = eigsh(A=KG, k=k, which='SM', M=K, tol=tol, sigma=1., mode=mode) msg('finished!', level=3, silent=silent) except Exception as e: warn(str(e), level=4, silent=silent) msg('aborted!', level=3, silent=silent) sizebkp = KG.shape[0] K, KG, used_cols = remove_null_cols(K, KG, silent=silent) msg('eigsh() solver...', level=3, silent=silent) eigvals, peigvecs = eigsh(A=KG, k=k, which='SM', M=K, tol=tol, sigma=1., mode=mode) msg('finished!', level=3, silent=silent) eigvecs = np.zeros((sizebkp, num_eigvalues), dtype=peigvecs.dtype) eigvecs[used_cols, :] = peigvecs else: size = KG.shape[0] K, KG, used_cols = remove_null_cols(K, KG, silent=silent) K = K.toarray() KG = KG.toarray() msg('eigh() solver...', level=3, silent=silent) eigvals, peigvecs = eigh(a=KG, b=K) msg('finished!', level=3, silent=silent) eigvecs = np.zeros((size, num_eigvalues), dtype=peigvecs.dtype) eigvecs[used_cols, :] = peigvecs[:, :num_eigvalues] eigvals = -1./eigvals eigvals = eigvals eigvecs = eigvecs msg('finished!', level=2, silent=silent) msg('first {0} eigenvalues:'.format(num_eigvalues_print), level=1, silent=silent) for eig in eigvals[:num_eigvalues_print]: msg('{0}'.format(eig), level=2, silent=silent) return eigvals, eigvecs