BandArpackSolver.cpp

Go to the documentation of this file.
00001 // Written: Jun Peng
00002 // Created: Feb. 11, 1999
00003 // Revision: A
00004 //
00005 // Description: This file contains the class definition for 
00006 // BandArpackSolver. It solves the BandArpackSOE object by calling
00007 // Arpack routines.
00008 
00009 #include <BandArpackSolver.h>
00010 #include <BandArpackSOE.h>
00011 #include <f2c.h>
00012 #include <math.h>
00013 #include <stdio.h>
00014 #include <AnalysisModel.h>
00015 #include <DOF_GrpIter.h>
00016 #include <DOF_Group.h>
00017 #include <FE_EleIter.h>
00018 #include <FE_Element.h>
00019 #include <Integrator.h>
00020 #include <string.h>
00021 
00022 BandArpackSolver::BandArpackSolver(int numE)
00023 :EigenSolver(EigenSOLVER_TAGS_BandArpackSolver),
00024  theNev(numE), value(0), eigenvector(0), iPiv(0), iPivSize(0), eigenV(0)
00025 {
00026   // do nothing here.    
00027 }
00028 
00029 
00030 BandArpackSolver::~BandArpackSolver()
00031 {
00032     if (iPiv != 0)
00033         delete [] iPiv;
00034     if (value != 0)
00035         delete [] value;
00036     if (eigenvector !=0)
00037         delete [] eigenvector;
00038     if (eigenV !=0)
00039         delete eigenV;
00040 }
00041 
00042 #ifdef _WIN32
00043 
00044 extern "C" int  DGBSV(int *N, int *KL, int *KU, int *NRHS, double *A, 
00045                               int *LDA, int *iPiv, double *B, int *LDB, 
00046                               int *INFO);
00047 
00048 extern "C" int  DGBTRF(int *M, int *N, int *KL, int *KU, double *A, int *LDA, 
00049                                int *iPiv, int *INFO);
00050 /*
00051 extern "C" int  DGBTRS(char *TRANS, unsigned int *sizeC, 
00052                                int *N, int *KL, int *KU, int *NRHS,
00053                                double *A, int *LDA, int *iPiv, 
00054                                double *B, int *LDB, int *INFO);
00055 
00056 extern "C" int  DSAUPD(int *ido, char* bmat, unsigned int *, 
00057                                int *n, char *which, unsigned int *,
00058                                int *nev, 
00059                                double *tol, double *resid, int *ncv, double *v, 
00060                                int *ldv,
00061                                int *iparam, int *ipntr, double *workd, double *workl,
00062                                int *lworkl, int *info);
00063 
00064 extern "C" int  DSEUPD(bool *rvec, char *howmny, unsigned int *,
00065                                logical *select, double *d, double *z,
00066                                int *ldz, double *sigma, char *bmat, unsigned int *,
00067                                int      *n, char *which, unsigned int *,
00068                                int *nev, double *tol, double *resid, int *ncv, 
00069                                double *v,
00070                                int *ldv, int *iparam, int *ipntr, double *workd, 
00071                                double *workl, int *lworkl, int *info);
00072 */
00073 
00074 extern "C" int  DGBTRS(char *TRANS, 
00075                                int *N, int *KL, int *KU, int *NRHS,
00076                                double *A, int *LDA, int *iPiv, 
00077                                double *B, int *LDB, int *INFO);
00078 
00079 extern "C" int  DSAUPD(int *ido, char* bmat, 
00080                                int *n, char *which,
00081                                int *nev, 
00082                                double *tol, double *resid, int *ncv, double *v, 
00083                                int *ldv,
00084                                int *iparam, int *ipntr, double *workd, double *workl,
00085                                int *lworkl, int *info);
00086 
00087 extern "C" int  DSEUPD(bool *rvec, char *howmny,
00088                                logical *select, double *d, double *z,
00089                                int *ldz, double *sigma, char *bmat,
00090                                int      *n, char *which,
00091                                int *nev, double *tol, double *resid, int *ncv, 
00092                                double *v,
00093                                int *ldv, int *iparam, int *ipntr, double *workd, 
00094                                double *workl, int *lworkl, int *info);
00095 
00096 #else
00097 
00098 extern "C" int dgbsv_(int *N, int *KL, int *KU, int *NRHS, double *A, int *LDA, 
00099                       int *iPiv, double *B, int *LDB, int *INFO);
00100 
00101 extern "C" int dgbtrf_(int *M, int *N, int *KL, int *KU, double *A, int *LDA, 
00102                        int *iPiv, int *INFO);
00103                        
00104 extern "C" int dgbtrs_(char *TRANS, int *N, int *KL, int *KU, int *NRHS, 
00105                        double *A, int *LDA, int *iPiv, double *B, int *LDB, 
00106                        int *INFO);
00107 
00108 extern "C" int dsaupd_(int *ido, char* bmat, int *n, char *which, int *nev, 
00109                        double *tol, double *resid, int *ncv, double *v, int *ldv,
00110                        int *iparam, int *ipntr, double *workd, double *workl,
00111                        int *lworkl, int *info);
00112 
00113 extern "C" int dseupd_(bool *rvec, char *howmny, logical *select, double *d, double *z,
00114                        int *ldz, double *sigma, char *bmat, int *n, char *which,
00115                        int *nev, double *tol, double *resid, int *ncv, double *v,
00116                        int *ldv, int *iparam, int *ipntr, double *workd, 
00117                        double *workl, int *lworkl, int *info);
00118 
00119 #endif
00120 
00121 
00122 
00123 
00124 int
00125 BandArpackSolver::solve(void)
00126 {
00127     if (theSOE == 0) {
00128         opserr << "WARNING BandGenLinLapackSolver::solve(void)- ";
00129         opserr << " No LinearSOE object has been set\n";
00130         return -1;
00131     }
00132 
00133     int n = theSOE->size;    
00134     
00135     // check iPiv is large enough
00136     if (iPivSize < n) {
00137         opserr << "WARNING BandGenLinLapackSolver::solve(void)- ";
00138         opserr << " iPiv not large enough - has setSize() been called?\n";
00139         return -1;
00140     }       
00141 
00142     // set some variables
00143     int kl = theSOE->numSubD;
00144     int ku = theSOE->numSuperD;
00145     int ldA = 2*kl + ku +1;
00146     int nrhs = 1;
00147     int ldB = n;
00148     int info;
00149     double *Aptr = theSOE->A;
00150     int    *iPIV = iPiv;
00151 
00152     int nev = theNev;
00153     int ncv = getNCV(n, nev);
00154 
00155     // set up the space for ARPACK functions.
00156     // this is done each time method is called!! .. this needs to be cleaned up
00157     int ldv = n;
00158     int lworkl = ncv*ncv + 8*ncv;
00159     double *v = new double[ldv * ncv];
00160     double *workl = new double[lworkl + 1];
00161     double *workd = new double[3 * n + 1];
00162     double *d = new double[nev];
00163     double *z= new double[n * nev];
00164     double *resid = new double[n];
00165     int *iparam = new int[11];
00166     int *ipntr = new int[11];
00167     logical *select = new logical[ncv];
00168 
00169     static char which[3]; strcpy(which, "LM");
00170     char bmat = 'G';
00171     char howmy = 'A';
00172 
00173     // some more variables
00174     int maxitr, mode;
00175     double tol = 0.0;
00176     info = 0;
00177     maxitr = 1000;
00178     mode = 3;
00179 
00180     iparam[0] = 1;
00181     iparam[2] = maxitr;
00182     iparam[6] = mode; 
00183 
00184     bool rvec = true;
00185 
00186     int ido = 0;
00187 
00188     int ierr = 0;
00189 
00190     // Do the factorization of Matrix (A-dM) here.
00191 #ifdef _WIN32
00192     DGBTRF(&n, &n, &kl, &ku, Aptr, &ldA, iPiv, &ierr); 
00193 #else
00194     dgbtrf_(&n, &n, &kl, &ku, Aptr, &ldA, iPiv, &ierr); 
00195 #endif
00196 
00197     if ( ierr != 0 ) {
00198        opserr << " BandArpackSolver::Error in dgbtrf_ " << endln;
00199        return -1;
00200     }
00201 
00202     while (1) { 
00203 
00204 #ifdef _WIN32
00205       unsigned int sizeWhich =2;
00206       unsigned int sizeBmat =1;
00207       unsigned int sizeHowmany =1;
00208           unsigned int sizeOne = 1;
00209           /*
00210       DSAUPD(&ido, &bmat, &sizeBmat, &n, which, &sizeWhich, &nev, &tol, resid, 
00211              &ncv, v, &ldv,
00212              iparam, ipntr, workd, workl, &lworkl, &info);
00213            */
00214           DSAUPD(&ido, &bmat, &n, which, &nev, &tol, resid, 
00215                  &ncv, v, &ldv,
00216                  iparam, ipntr, workd, workl, &lworkl, &info);
00217 #else
00218           dsaupd_(&ido, &bmat, &n, which, &nev, &tol, resid, &ncv, v, &ldv,
00219                   iparam, ipntr, workd, workl, &lworkl, &info);
00220 #endif
00221 
00222       if (ido == -1) {
00223 
00224           myMv(n, &workd[ipntr[0]-1], &workd[ipntr[1]-1]); 
00225 #ifdef _WIN32
00226           /*
00227           DGBTRS("N", &sizeOne, &n, &kl, &ku, &nrhs, Aptr, &ldA, iPIV, 
00228                  &workd[ipntr[1] - 1], &ldB, &ierr);
00229                  */
00230           DGBTRS("N", &n, &kl, &ku, &nrhs, Aptr, &ldA, iPIV, 
00231                  &workd[ipntr[1] - 1], &ldB, &ierr);
00232 #else
00233           dgbtrs_("N", &n, &kl, &ku, &nrhs, Aptr, &ldA, iPIV, 
00234                   &workd[ipntr[1] - 1], &ldB, &ierr);
00235 #endif
00236 
00237           if (ierr != 0) {
00238               opserr << "BandArpackSolver::Error with dgbtrs_ 1" <<endln;
00239               exit(0);
00240           }
00241           continue;
00242       } else if (ido == 1) {
00243 
00244         //          double ratio = 1.0;
00245           myCopy(n, &workd[ipntr[2]-1], &workd[ipntr[1]-1]);
00246 
00247 #ifdef _WIN32
00248           /*
00249           DGBTRS("N", &sizeOne, &n, &kl, &ku, &nrhs, Aptr, &ldA, iPIV, 
00250                  &workd[ipntr[1] - 1], &ldB, &ierr);
00251                  */
00252           DGBTRS("N", &n, &kl, &ku, &nrhs, Aptr, &ldA, iPIV, 
00253                  &workd[ipntr[1] - 1], &ldB, &ierr);
00254 #else
00255           dgbtrs_("N", &n, &kl, &ku, &nrhs, Aptr, &ldA, iPIV, 
00256                   &workd[ipntr[1] - 1], &ldB, &ierr);
00257 #endif
00258 
00259           if (ierr != 0) {
00260               opserr << "BandArpackSolver::Error with dgbtrs_ 2" <<endln;
00261               exit(0);
00262           }
00263           continue;
00264       } else if (ido == 2) {     
00265 
00266           myMv(n, &workd[ipntr[0]-1], &workd[ipntr[1]-1]);
00267           continue;
00268       }
00269 
00270       break;
00271     }
00272 
00273     if (info < 0) {
00274       opserr << "BandArpackSolver::Error with _saupd info = " << info << endln;
00275       switch(info) {
00276 
00277          case -1: 
00278            opserr << "N must be positive.\n";
00279            break;
00280          case -2: 
00281            opserr << "NEV must be positive.\n";
00282            break;
00283          case -3: 
00284            opserr << "NCV must be greater than NEV and less than or equal to N.\n";
00285            break;
00286          case -4:
00287            opserr << "The maximum number of Arnoldi update iterations allowed";
00288            break;
00289          case -5: 
00290            opserr << "WHICH must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'.\n";
00291            break;
00292          case -6: 
00293            opserr << "BMAT must be one of 'I' or 'G'.\n";
00294            break;
00295          case -7: 
00296            opserr << "Length of private work array WORKL is not sufficient.\n";
00297            break;
00298          case -8: 
00299            opserr << "Error return from trid. eigenvalue calculation";
00300            opserr << "Informatinal error from LAPACK routine dsteqr.\n";
00301            break;
00302          case -9: 
00303            opserr << "Starting vector is zero.\n";
00304            break;
00305          case -10: 
00306            opserr << "IPARAM(7) must be 1,2,3,4,5.\n";
00307            break;
00308          case -11: 
00309            opserr << "IPARAM(7) = 1 and BMAT = 'G' are incompatable.\n";
00310            break;
00311          case -12: 
00312            opserr << "IPARAM(1) must be equal to 0 or 1.\n";
00313            break;
00314          case -13:
00315            opserr << "NEV and WHICH = 'BE' are incompatable.\n";
00316            break;
00317          case -9999:
00318            opserr << "Could not build an Arnoldi factorization.";
00319            opserr << "IPARAM(5) returns the size of the current Arnoldi\n";
00320            opserr << "factorization. The user is advised to check that";
00321            opserr << "enough workspace and array storage has been allocated.\n";
00322            break;
00323          default:
00324            opserr << "unrecognised return value\n";
00325       }
00326 
00327       // clean up the memory
00328       delete [] workl;
00329       delete [] workd;
00330       delete [] resid;
00331       delete [] iparam;
00332       delete [] v;
00333       delete [] select;
00334       delete [] ipntr;
00335       delete [] d;
00336       delete [] z;
00337 
00338       value = 0;
00339       eigenvector = 0;
00340                 
00341       return info;
00342     } else {
00343         if (info == 1) {
00344           opserr << "BandArpackSolver::Maximum number of iteration reached." << endln;
00345         } else if (info == 3) {
00346           opserr << "BandArpackSolver::No Shifts could be applied during implicit,";
00347           opserr << "Arnoldi update, try increasing NCV." << endln;
00348         }
00349 
00350         double sigma = theSOE->shift;
00351         if (iparam[4] > 0) {
00352             rvec = true;
00353             n = theSOE->size;    
00354             ldv = n;
00355 
00356 #ifdef _WIN32
00357             unsigned int sizeWhich =2;
00358             unsigned int sizeBmat =1;
00359             unsigned int sizeHowmany =1;
00360                 /*
00361             DSEUPD(&rvec, &howmy, &sizeHowmany, select, d, z, &ldv, &sigma, &bmat,
00362                    &sizeBmat, &n, which, &sizeWhich,
00363                    &nev, &tol, resid, &ncv, v, &ldv, iparam, ipntr, workd,
00364                    workl, &lworkl, &info);
00365                    */
00366                 DSEUPD(&rvec, &howmy, select, d, z, &ldv, &sigma, &bmat, &n, which,
00367                    &nev, &tol, resid, &ncv, v, &ldv, iparam, ipntr, workd,
00368                    workl, &lworkl, &info);
00369 #else
00370             dseupd_(&rvec, &howmy, select, d, z, &ldv, &sigma, &bmat, &n, which,
00371                     &nev, &tol, resid, &ncv, v, &ldv, iparam, ipntr, workd,
00372                     workl, &lworkl, &info);
00373 #endif
00374             if (info != 0) {
00375                 opserr << "BandArpackSolver::Error with dseupd_" << info;
00376                 switch(info) {
00377 
00378                 case -1: 
00379                    opserr << " N must be positive.\n";
00380                    break;
00381                 case -2: 
00382                    opserr << " NEV must be positive.\n";
00383                    break;
00384                 case -3: 
00385                    opserr << " NCV must be greater than NEV and less than or equal to N.\n";
00386                    break;
00387                 case -5: 
00388                    opserr << " WHICH must be one of 'LM', 'SM', 'LA', 'SA' or 'BE'.\n";
00389                    break;
00390                 case -6: 
00391                    opserr << " BMAT must be one of 'I' or 'G'.\n";
00392                    break;
00393                 case -7: 
00394                    opserr << " Length of private work WORKL array is not sufficient.\n";
00395                    break;
00396                 case -8: 
00397                    opserr << " Error return from trid. eigenvalue calculation";
00398                    opserr << "Information error from LAPACK routine dsteqr.\n";
00399                    break;
00400                 case -9: 
00401                    opserr << " Starting vector is zero.\n";
00402                    break;
00403                 case -10: 
00404                    opserr << " IPARAM(7) must be 1,2,3,4,5.\n";
00405                    break;
00406                 case -11: 
00407                    opserr << " IPARAM(7) = 1 and BMAT = 'G' are incompatibl\n";
00408                    break;
00409                 case -12: 
00410                    opserr << " NEV and WHICH = 'BE' are incompatible.\n";
00411                    break;
00412                 case -14: 
00413                    opserr << " DSAUPD did not find any eigenvalues to sufficient accuracy.\n";
00414                    break;
00415                 case -15: 
00416                    opserr << " HOWMNY must be one of 'A' or 'S' if RVEC = .true.\n";
00417                    break;
00418                 case -16: 
00419                    opserr << " HOWMNY = 'S' not yet implemented\n";
00420                    break;
00421                 default:
00422                   ;
00423                 }
00424 
00425                 // clean up the memory
00426                 delete [] workl;
00427                 delete [] workd;
00428                 delete [] resid;
00429                 delete [] iparam;
00430                 delete [] v;
00431                 delete [] select;
00432                 delete [] ipntr;
00433                 delete [] d;
00434                 delete [] z;
00435 
00436                 value = 0;
00437                 eigenvector = 0;
00438 
00439                 return info;
00440 
00441             }
00442         }
00443     }
00444 
00445 
00446     value = d;
00447     eigenvector = z;
00448 
00449     theSOE->factored = true;
00450 
00451     // clean up the memory
00452     delete [] workl;
00453     delete [] workd;
00454     delete [] resid;
00455     delete [] iparam;
00456     delete [] v;
00457     delete [] select;
00458     delete [] ipntr;
00459 
00460     return 0;
00461 }
00462 
00463 
00464 int 
00465 BandArpackSolver::getNCV(int n, int nev)
00466 {
00467     int result;
00468     if (2*nev > nev+8) {
00469         result = nev+8;
00470     } else {
00471         result = 2*nev;
00472     }
00473 
00474     if (result >= n) {
00475         result = n;
00476     }
00477 
00478     return result;
00479 }
00480 
00481 
00482 void
00483 BandArpackSolver::myMv(int n, double *v, double *result)
00484 {
00485     Vector x(v, n);
00486     Vector y(result,n);
00487 
00488     y.Zero();
00489     AnalysisModel *theAnalysisModel = theSOE->theModel;
00490 
00491     // loop over the FE_Elements
00492     FE_Element *elePtr;
00493     FE_EleIter &theEles = theAnalysisModel->getFEs();    
00494     while((elePtr = theEles()) != 0) {
00495       const Vector &b = elePtr->getM_Force(x, 1.0);
00496       y.Assemble(b, elePtr->getID(), 1.0);
00497     }
00498 
00499     // loop over the DOF_Groups
00500     DOF_Group *dofPtr;
00501     DOF_GrpIter &theDofs = theAnalysisModel->getDOFs();
00502     Integrator *theIntegrator = 0;
00503     while ((dofPtr = theDofs()) != 0) {
00504       const Vector &a = dofPtr->getM_Force(x,1.0);      
00505       y.Assemble(a,dofPtr->getID(),1.0);
00506     }
00507 }
00508 
00509 void
00510 BandArpackSolver::myCopy(int n, double *v, double *result)
00511 {
00512     for (int i=0; i<n; i++) {
00513         result[i] = v[i];
00514     }
00515 }
00516 
00517 
00518 int
00519 BandArpackSolver::setEigenSOE(BandArpackSOE &theBandSOE)
00520 {
00521     theSOE = &theBandSOE;
00522     return 0;
00523 }
00524 
00525 
00526 const Vector &
00527 BandArpackSolver::getEigenvector(int mode)
00528 {
00529     if (mode <= 0 || mode > theNev) {
00530         opserr << "BandArpackSOE::getEigenvector() - mode is out of range(1 - nev)";
00531         eigenV->Zero();
00532         return *eigenV;  
00533     }
00534 
00535     int size = theSOE->size;
00536     int index = (mode - 1) * size;
00537 
00538     if (eigenvector != 0) {
00539       for (int i=0; i<size; i++) {
00540         (*eigenV)[i] = eigenvector[index++];
00541       } 
00542     }
00543     else {
00544         opserr << "BandArpackSOE::getEigenvalue() - eigenvectors not yet determined";
00545         eigenV->Zero();
00546     }      
00547 
00548     //Vector *eigenV = new Vector(&vector[index], size);
00549     return *eigenV;  
00550 }
00551 
00552 
00553 double
00554 BandArpackSolver::getEigenvalue(int mode)
00555 {
00556     if (mode <= 0 || mode > theNev) {
00557         opserr << "BandArpackSOE::getEigenvalue() - mode is out of range(1 - nev)";
00558         return -1;
00559     }
00560 
00561     if (value != 0)
00562       return value[mode-1];
00563     else {
00564         opserr << "BandArpackSOE::getEigenvalue() - eigenvalues not yet determined";
00565         return -2;
00566     }      
00567 }
00568   
00569 
00570 int
00571 BandArpackSolver::setSize()
00572 {
00573     // if iPiv not big enough, free it and get one large enough
00574     int size = theSOE->size;    
00575     if (iPivSize < size) {
00576         if (iPiv != 0)
00577             delete [] iPiv;
00578         
00579         iPiv = new int[size];
00580         if (iPiv == 0) {
00581             opserr << "WARNING BandGenLinLapackSolver::setSize() ";
00582             opserr << " - ran out of memory for iPiv of size ";
00583             opserr << theSOE->size << endln;
00584             return -1;
00585         } else
00586             iPivSize = size;
00587     }
00588     
00589     if (eigenV == 0 || eigenV->Size() != size) {
00590         if (eigenV != 0)
00591             delete eigenV;
00592 
00593         eigenV = new Vector(size);
00594         if (eigenV == 0 || eigenV->Size() != size) {
00595             opserr << "WARNING BandGenLinLapackSolver::setSize() ";
00596             opserr << " - ran out of memory for eigenVector of size ";
00597             opserr << theSOE->size << endln;
00598             return -2;      
00599         }
00600     }
00601             
00602     return 0;
00603 }
00604 
00605 
00606 int    
00607 BandArpackSolver::sendSelf(int commitTag, Channel &theChannel)
00608 {
00609     return 0;
00610 }
00611 
00612 int
00613 BandArpackSolver::recvSelf(int commitTag, Channel &theChannel, 
00614                            FEM_ObjectBroker &theBroker)
00615 {
00616     // nothing to do
00617     return 0;
00618 }
00619 
00620  
00621 

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