SymBandEigenSolver.cpp

Go to the documentation of this file.
00001 /* ****************************************************************** **
00002 **    OpenSees - Open System for Earthquake Engineering Simulation    **
00003 **          Pacific Earthquake Engineering Research Center            **
00004 **                                                                    **
00005 **                                                                    **
00006 ** (C) Copyright 1999, The Regents of the University of California    **
00007 ** All Rights Reserved.                                               **
00008 **                                                                    **
00009 ** Commercial use of this program without express permission of the   **
00010 ** University of California, Berkeley, is strictly prohibited.  See   **
00011 ** file 'COPYRIGHT'  in main directory for information on usage and   **
00012 ** redistribution,  and for a DISCLAIMER OF ALL WARRANTIES.           **
00013 **                                                                    **
00014 ** Developed by:                                                      **
00015 **   Frank McKenna (fmckenna@ce.berkeley.edu)                         **
00016 **   Gregory L. Fenves (fenves@ce.berkeley.edu)                       **
00017 **   Filip C. Filippou (filippou@ce.berkeley.edu)                     **
00018 **                                                                    **
00019 ** ****************************************************************** */
00020                                                                         
00021 // $Revision: 1.7 $
00022 // $Date: 2005/07/06 22:00:20 $
00023 // $Source: /usr/local/cvs/OpenSees/SRC/system_of_eqn/eigenSOE/SymBandEigenSolver.cpp,v $
00024 
00025 // Written: MHS
00026 // Created: Oct 2001
00027 //
00028 // Description: This file contains the class definition for
00029 // SymBandEigenSolver, which computes the eigenvalues and eigenvectors
00030 // of a symmetric banded matrix using the LAPACK subroutine dsbevx.
00031 
00032 #include <SymBandEigenSolver.h>
00033 #include <f2c.h>
00034 #include <math.h>
00035 #include <stdio.h>
00036 #include <AnalysisModel.h>
00037 #include <DOF_GrpIter.h>
00038 #include <DOF_Group.h>
00039 #include <FE_EleIter.h>
00040 #include <FE_Element.h>
00041 #include <Integrator.h>
00042 
00043 SymBandEigenSolver::SymBandEigenSolver()
00044 :EigenSolver(EigenSOLVER_TAGS_SymBandEigenSolver),
00045  theSOE(0), numModes(0), eigenvalue(0), eigenvector(0), eigenV(0)
00046 {
00047 
00048 }
00049 
00050 SymBandEigenSolver::~SymBandEigenSolver()
00051 {
00052   if (eigenvalue != 0)
00053     delete [] eigenvalue;
00054   if (eigenvector != 0)
00055     delete [] eigenvector;
00056   if (eigenV != 0)
00057     delete eigenV;
00058 }
00059 
00060 #ifdef _WIN32
00061 
00062 extern "C" int DSBEVX(char *jobz, char *range, char *uplo, int *n, int *kd,
00063                                double *ab, int *ldab, double *q, int *ldq,
00064                                double *vl, double *vu, int *il, int *iu, double *abstol,
00065                                int *m, double *w, double *z, int *ldz,
00066                                double *work, int *iwork, int *ifail, int *info);
00067 
00068 #else
00069 
00070 extern "C" int dsbevx_(char *jobz, char *range, char *uplo, int *n, int *kd,
00071                        double *ab, int *ldab, double *q, int *ldq,
00072                        double *vl, double *vu, int *il, int *iu, double *abstol,
00073                        int *m, double *w, double *z, int *ldz,
00074                        double *work, int *iwork, int *ifail, int *info);
00075 
00076 #endif
00077 
00078 int
00079 SymBandEigenSolver::solve(int nModes)
00080 {
00081   if (theSOE == 0) {
00082     opserr << "SymBandEigenSolver::solve() -- no EigenSOE has been set yet\n";
00083     return -1;
00084   }
00085   
00086   // Set number of modes
00087   numModes = nModes;
00088 
00089   // Number of equations
00090   int n = theSOE->size;
00091 
00092   // Check for quick return
00093   if (numModes < 1) {
00094     numModes = 0;
00095     return 0;
00096   }
00097 
00098   // Simple check
00099   if (numModes > n)
00100     numModes = n;
00101 
00102   // Allocate storage for eigenvalues
00103   if (eigenvalue != 0)
00104     delete [] eigenvalue;
00105   eigenvalue = new double [n];
00106 
00107   // Real work array (see LAPACK dsbevx subroutine documentation)
00108   double *work = new double [7*n];
00109 
00110   // Integer work array (see LAPACK dsbevx subroutine documentation)
00111   int *iwork = new int [5*n];
00112 
00113   // Leading dimension of eigenvectors
00114   int ldz = n;
00115 
00116   // Allocate storage for eigenvectors
00117   if (eigenvector != 0)
00118     delete [] eigenvector;
00119   eigenvector = new double [ldz*numModes];
00120 
00121   // Number of superdiagonals
00122   int kd = theSOE->numSuperD;
00123 
00124   // Matrix data
00125   double *ab = theSOE->A;
00126 
00127   // Leading dimension of the matrix
00128   int ldab = kd + 1;
00129 
00130   // Leading dimension of q
00131   int ldq = n;
00132 
00133   // Orthogonal matrix used in reduction to tridiagonal form
00134   // (see LAPACK dsbevx subroutine documentation)
00135   double *q = new double [ldq*n];
00136 
00137   // Index ranges [1,numModes] of eigenpairs to compute
00138   int il = 1;
00139   int iu = numModes;
00140 
00141   // Compute eigenvalues and eigenvectors
00142   char *jobz = "V";
00143 
00144   // Selected eigenpairs are based on index range [il,iu]
00145   char *range = "I";
00146 
00147   // Upper triagle of matrix is stored
00148   char *uplo = "U";
00149   
00150   // Return value
00151   int *ifail = new int [n];
00152   int info = 0;
00153 
00154   // Number of eigenvalues returned
00155   int m = 0;
00156 
00157   // Not used
00158   double vl = 0.0;
00159   double vu = 1.0;
00160 
00161   // Not used ... I think!
00162   double abstol = -1.0;
00163 
00164 
00165   // if Mass matrix we make modifications to A:
00166   //         A -> M^(-1/2) A M^(-1/2)
00167   double *M = theSOE->M;
00168   double *A = theSOE->A;
00169   int numSuperD = theSOE->numSuperD;
00170   int size = n;
00171   if (M != 0) {
00172     int i,j;
00173     bool singular = false;
00174     // form M^(-1/2) and check for singular mass matrix
00175     for (int k=0; k<size; k++) {
00176       if (M[k] == 0.0) {
00177         singular = true;
00178         // alternative is to set as a small no ~ 1e-10 times smallest m(i,i) != 0.0
00179         opserr << "SymBandEigenSolver::solve() - M matrix singular\n";
00180         return -1;
00181       } else {
00182         M[k] = 1.0/sqrt(M[k]);
00183       }
00184     }
00185 
00186     // make modifications to A
00187     //   Aij -> Mi Aij Mj  (based on new M)
00188     for (i=0; i<size; i++) {
00189       double *AijPtr = A +(i+1)*(numSuperD+1) - 1;
00190       int minColRow = i - numSuperD;
00191       if (minColRow < 0) minColRow = 0;
00192       for (j=i; j>=minColRow; j--) {
00193         *AijPtr *= M[j]*M[i];
00194         AijPtr--;
00195       }
00196     }
00197   }
00198 
00199   // Call the LAPACK eigenvalue subroutine
00200 #ifdef _WIN32
00201   unsigned int sizeC = 1;
00202   DSBEVX(jobz, range, uplo, &n, &kd, ab, &ldab,
00203          q, &ldq, &vl, &vu, &il, &iu, &abstol, &m,
00204          eigenvalue, eigenvector, &ldz, work, iwork, ifail, &info);
00205 #else
00206   dsbevx_(jobz, range, uplo, &n, &kd, ab, &ldab,
00207           q, &ldq, &vl, &vu, &il, &iu, &abstol, &m,
00208           eigenvalue, eigenvector, &ldz, work, iwork, ifail, &info);
00209 #endif
00210 
00211   delete [] q;
00212   delete [] work;
00213   delete [] iwork;
00214   delete [] ifail;
00215 
00216   if (info < 0) {
00217     opserr << "SymBandEigenSolver::solve() -- invalid argument number " << -info << " passed to LAPACK dsbevx\n";
00218     return info;
00219   }
00220 
00221   if (info > 0) {
00222     opserr << "SymBandEigenSolver::solve() -- LAPACK dsbevx returned error code " << info << endln;
00223     return -info;
00224   }
00225 
00226   if (m < numModes) {
00227     opserr << "SymBandEigenSolver::solve() -- LAPACK dsbevx only computed " << m << " eigenvalues, " <<
00228       numModes << "were requested\n";
00229 
00230     numModes = m;
00231   }
00232 
00233   theSOE->factored = true;
00234 
00235   // make modifications to the eigenvectors
00236   //   Eij -> Mi Eij  (based on new M)
00237 
00238 
00239   M = theSOE->M;
00240   if (M != 0) {
00241     
00242     for (int j=0; j<numModes; j++) {
00243       double *eigVectJptr = &eigenvector[j*ldz];
00244       double *MPtr = M;
00245       for (int i=0; i<size; i++) 
00246         *eigVectJptr++ *= *MPtr++;
00247     }
00248   }
00249 
00250   return 0;
00251 }
00252 
00253 int
00254 SymBandEigenSolver::setEigenSOE(SymBandEigenSOE &theBandSOE)
00255 {
00256   theSOE = &theBandSOE;
00257 
00258   return 0;
00259 }
00260 
00261 const Vector &
00262 SymBandEigenSolver::getEigenvector(int mode)
00263 {
00264   if (mode < 1 || mode > numModes) {
00265     opserr << "SymBandEigenSolver::getEigenVector() -- mode " << mode << " is out of range (1 - "
00266            << numModes << ")\n";
00267 
00268     eigenV->Zero();
00269     return *eigenV;  
00270   }
00271   
00272   int size = theSOE->size;
00273 
00274   int index = (mode - 1) * size;
00275   
00276   Vector &vec = *eigenV;
00277   if (eigenvector != 0) {
00278     for (int i = 0; i < size; i++) {
00279       vec(i) = eigenvector[index++];
00280     }   
00281   }
00282   else {
00283     opserr << "SymBandEigenSolver::getEigenVector() -- eigenvectors not yet computed\n";
00284     eigenV->Zero();
00285   }      
00286   
00287   return *eigenV;  
00288 }
00289 
00290 double
00291 SymBandEigenSolver::getEigenvalue(int mode)
00292 {
00293   if (mode < 1 || mode > numModes) {
00294     opserr << "SymBandEigenSolver::getEigenvalue() -- mode " << mode << " is out of range (1 - "
00295            << numModes << ")\n";
00296 
00297     return 0.0;
00298   }
00299   
00300   if (eigenvalue != 0)
00301     return eigenvalue[mode-1];
00302   else {
00303     opserr << "SymBandEigenSolver::getEigenvalue() -- eigenvalues not yet computed\n";
00304     return 0.0;
00305   }      
00306 }
00307 
00308 int
00309 SymBandEigenSolver::setSize()
00310 {
00311   int size = theSOE->size;    
00312 
00313   if (eigenV == 0 || eigenV->Size() != size) {
00314     if (eigenV != 0)
00315       delete eigenV;
00316     
00317     eigenV = new Vector(size);
00318     if (eigenV == 0 || eigenV->Size() != size) {
00319       opserr << "SymBandEigenSolver::ssetSize() -- ran out of memory for eigenvector of size " << size << endln;
00320       return -2;            
00321     }
00322   }
00323   
00324   return 0;
00325 }
00326 
00327 int    
00328 SymBandEigenSolver::sendSelf(int commitTag, Channel &theChannel)
00329 {
00330   return 0;
00331 }
00332 
00333 int
00334 SymBandEigenSolver::recvSelf(int commitTag, Channel &theChannel, 
00335                              FEM_ObjectBroker &theBroker)
00336 {
00337   return 0;
00338 }

Generated on Mon Oct 23 15:05:27 2006 for OpenSees by doxygen 1.5.0