00001
00002
00003
00004
00005
00006
00007
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
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
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
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
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
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
00156
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
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
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
00211
00212
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
00228
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
00245 myCopy(n, &workd[ipntr[2]-1], &workd[ipntr[1]-1]);
00246
00247 #ifdef _WIN32
00248
00249
00250
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
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
00362
00363
00364
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
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
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
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
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
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
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
00617 return 0;
00618 }
00619
00620
00621