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