AnasaziLOBPCGSolMgr.hpp

Go to the documentation of this file.
00001 
00002 // @HEADER
00003 // ***********************************************************************
00004 //
00005 //                 Anasazi: Block Eigensolvers Package
00006 //                 Copyright (2004) Sandia Corporation
00007 //
00008 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00009 // license for use of this work by or on behalf of the U.S. Government.
00010 //
00011 // This library is free software; you can redistribute it and/or modify
00012 // it under the terms of the GNU Lesser General Public License as
00013 // published by the Free Software Foundation; either version 2.1 of the
00014 // License, or (at your option) any later version.
00015 //
00016 // This library is distributed in the hope that it will be useful, but
00017 // WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 // Lesser General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License along with this library; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00024 // USA
00025 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00026 //
00027 // ***********************************************************************
00028 // @HEADER
00029 
00030 #ifndef ANASAZI_LOBPCG_SOLMGR_HPP
00031 #define ANASAZI_LOBPCG_SOLMGR_HPP
00032 
00037 #include "AnasaziConfigDefs.hpp"
00038 #include "AnasaziTypes.hpp"
00039 
00040 #include "AnasaziEigenproblem.hpp"
00041 #include "AnasaziSolverManager.hpp"
00042 
00043 #include "AnasaziSolverUtils.hpp"
00044 
00045 #include "AnasaziLOBPCG.hpp"
00046 #include "AnasaziBasicSort.hpp"
00047 #include "AnasaziSVQBOrthoManager.hpp"
00048 #include "AnasaziStatusTestMaxIters.hpp"
00049 #include "AnasaziStatusTestResNorm.hpp"
00050 #include "AnasaziStatusTestOrderedResNorm.hpp"
00051 #include "AnasaziStatusTestCombo.hpp"
00052 #include "AnasaziStatusTestOutput.hpp"
00053 #include "AnasaziBasicOutputManager.hpp"
00054 
00055 
00083 namespace Anasazi {
00084 
00085 template<class ScalarType, class MV, class OP>
00086 class LOBPCGSolMgr : public SolverManager<ScalarType,MV,OP> {
00087 
00088   private:
00089     typedef MultiVecTraits<ScalarType,MV> MVT;
00090     typedef OperatorTraits<ScalarType,MV,OP> OPT;
00091     typedef Teuchos::ScalarTraits<ScalarType> SCT;
00092     typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
00093     typedef Teuchos::ScalarTraits<MagnitudeType> MT;
00094     
00095   public:
00096 
00098 
00099 
00119   LOBPCGSolMgr( const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
00120                              Teuchos::ParameterList &pl );
00121 
00123   virtual ~LOBPCGSolMgr() {};
00125   
00127 
00128 
00129   const Eigenproblem<ScalarType,MV,OP>& getProblem() const {
00130     return *problem_;
00131   }
00132 
00134 
00136 
00137     
00164   ReturnType solve();
00166 
00167   private:
00168   Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > problem_;
00169 
00170   std::string whch_; 
00171 
00172   MagnitudeType convtol_, locktol_;
00173   int maxIters_;
00174   bool useLocking_;
00175   bool relconvtol_, rellocktol_;
00176   int blockSize_;
00177   bool fullOrtho_;
00178   int maxLocked_;
00179   int verbosity_;
00180   int lockQuorum_;
00181   bool recover_;
00182   Teuchos::RCP<LOBPCGState<ScalarType,MV> > state_;
00183 };
00184 
00185 
00186 // Constructor
00187 template<class ScalarType, class MV, class OP>
00188 LOBPCGSolMgr<ScalarType,MV,OP>::LOBPCGSolMgr( 
00189         const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
00190         Teuchos::ParameterList &pl ) : 
00191   problem_(problem),
00192   whch_("SR"),
00193   convtol_(MT::prec()),
00194   maxIters_(100),
00195   useLocking_(false),
00196   relconvtol_(true),
00197   rellocktol_(true),
00198   blockSize_(0),
00199   fullOrtho_(true),
00200   maxLocked_(0),
00201   verbosity_(Anasazi::Errors),
00202   lockQuorum_(1),
00203   recover_(true)
00204 {
00205   TEST_FOR_EXCEPTION(problem_ == Teuchos::null,              std::invalid_argument, "Problem not given to solver manager.");
00206   TEST_FOR_EXCEPTION(!problem_->isProblemSet(),              std::invalid_argument, "Problem not set.");
00207   TEST_FOR_EXCEPTION(!problem_->isHermitian(),               std::invalid_argument, "Problem not symmetric.");
00208   TEST_FOR_EXCEPTION(problem_->getInitVec() == Teuchos::null,std::invalid_argument, "Problem does not contain initial vectors to clone from.");
00209 
00210 
00211   // which values to solve for
00212   whch_ = pl.get("Which",whch_);
00213   TEST_FOR_EXCEPTION(whch_ != "SM" && whch_ != "LM" && whch_ != "SR" && whch_ != "LR",std::invalid_argument, "Invalid sorting string.");
00214 
00215   // convergence tolerance
00216   convtol_ = pl.get("Convergence Tolerance",convtol_);
00217   relconvtol_ = pl.get("Relative Convergence Tolerance",relconvtol_);
00218   
00219   // locking tolerance
00220   useLocking_ = pl.get("Use Locking",useLocking_);
00221   rellocktol_ = pl.get("Relative Locking Tolerance",rellocktol_);
00222   // default: should be less than convtol_
00223   locktol_ = convtol_/10;
00224   locktol_ = pl.get("Locking Tolerance",locktol_);
00225 
00226   // maximum number of iterations
00227   maxIters_ = pl.get("Maximum Iterations",maxIters_);
00228 
00229   // block size: default is nev()
00230   blockSize_ = pl.get("Block Size",problem_->getNEV());
00231   TEST_FOR_EXCEPTION(blockSize_ <= 0, std::invalid_argument,
00232                      "Anasazi::LOBPCGSolMgr: \"Block Size\" must be strictly positive.");
00233 
00234   // max locked: default is nev(), must satisfy maxLocked_ + blockSize_ >= nev
00235   if (useLocking_) {
00236     maxLocked_ = pl.get("Max Locked",problem_->getNEV());
00237   }
00238   else {
00239     maxLocked_ = 0;
00240   }
00241   if (maxLocked_ == 0) {
00242     useLocking_ = false;
00243   }
00244   TEST_FOR_EXCEPTION(maxLocked_ < 0, std::invalid_argument,
00245                      "Anasazi::LOBPCGSolMgr: \"Max Locked\" must be positive.");
00246   TEST_FOR_EXCEPTION(maxLocked_ + blockSize_ < problem_->getNEV(), 
00247                      std::invalid_argument,
00248                      "Anasazi::LOBPCGSolMgr: Not enough storage space for requested number of eigenpairs.");
00249 
00250   if (useLocking_) {
00251     lockQuorum_ = pl.get("Locking Quorum",lockQuorum_);
00252     TEST_FOR_EXCEPTION(lockQuorum_ <= 0,
00253                        std::invalid_argument,
00254                        "Anasazi::LOBPCGSolMgr: \"Locking Quorum\" must be strictly positive.");
00255   }
00256 
00257   // full orthogonalization: default true
00258   fullOrtho_ = pl.get("Full Ortho",fullOrtho_);
00259 
00260   // verbosity level
00261   if (pl.isParameter("Verbosity")) {
00262     if (Teuchos::isParameterType<int>(pl,"Verbosity")) {
00263       verbosity_ = pl.get("Verbosity", verbosity_);
00264     } else {
00265       verbosity_ = (int)Teuchos::getParameter<Anasazi::MsgType>(pl,"Verbosity");
00266     }
00267   }
00268 
00269   // recover from LOBPCGRitzFailure
00270   recover_ = pl.get("Recover",recover_);
00271 
00272   // get (optionally) an initial state
00273   if (pl.isParameter("Init")) {
00274     state_ = Teuchos::getParameter<Teuchos::RCP<Anasazi::LOBPCGState<ScalarType,MV> > >(pl,"Init");
00275   }
00276 }
00277 
00278 
00279 // solve()
00280 template<class ScalarType, class MV, class OP>
00281 ReturnType 
00282 LOBPCGSolMgr<ScalarType,MV,OP>::solve() {
00283 
00284   const int nev = problem_->getNEV();
00285 
00286 
00287 
00289   // Sort manager
00290   Teuchos::RCP<BasicSort<ScalarType,MV,OP> > sorter = Teuchos::rcp( new BasicSort<ScalarType,MV,OP>(whch_) );
00291 
00293   // Output manager
00294   Teuchos::RCP<BasicOutputManager<ScalarType> > printer = Teuchos::rcp( new BasicOutputManager<ScalarType>(verbosity_) );
00295 
00297   // Status tests
00298   //
00299   // maximum number of iterations: optional test
00300   Teuchos::RCP<StatusTestMaxIters<ScalarType,MV,OP> > maxtest;
00301   if (maxIters_ > 0) {
00302     maxtest = Teuchos::rcp( new StatusTestMaxIters<ScalarType,MV,OP>(maxIters_) );
00303   }
00304   // convergence
00305   Teuchos::RCP<StatusTestOrderedResNorm<ScalarType,MV,OP> > convtest 
00306       = Teuchos::rcp( new StatusTestOrderedResNorm<ScalarType,MV,OP>(sorter,convtol_,nev,StatusTestOrderedResNorm<ScalarType,MV,OP>::RES_ORTH,relconvtol_) );
00307   // locking
00308   Teuchos::RCP<StatusTestResNorm<ScalarType,MV,OP> > locktest;
00309   if (useLocking_) {
00310     locktest = Teuchos::rcp( new StatusTestResNorm<ScalarType,MV,OP>(locktol_,lockQuorum_,StatusTestResNorm<ScalarType,MV,OP>::RES_ORTH,rellocktol_) );
00311   }
00312   Teuchos::Array<Teuchos::RCP<StatusTest<ScalarType,MV,OP> > > alltests;
00313   // for an OR test, the order doesn't matter
00314   alltests.push_back(convtest);
00315   if (maxtest != Teuchos::null) alltests.push_back(maxtest);
00316   if (locktest != Teuchos::null)   alltests.push_back(locktest);
00317   // combo: convergence || locking || max iters
00318   Teuchos::RCP<StatusTestCombo<ScalarType,MV,OP> > combotest
00319     = Teuchos::rcp( new StatusTestCombo<ScalarType,MV,OP>( StatusTestCombo<ScalarType,MV,OP>::OR, alltests) );
00320   // printing StatusTest
00321   Teuchos::RCP<StatusTestOutput<ScalarType,MV,OP> > outputtest;
00322   if ( printer->isVerbosity(Debug) ) {
00323     outputtest = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer,combotest,1,Passed+Failed+Undefined ) );
00324   }
00325   else {
00326     outputtest = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer,combotest,1,Passed ) );
00327   }
00328 
00330   // Orthomanager
00331   Teuchos::RCP<SVQBOrthoManager<ScalarType,MV,OP> > ortho 
00332     = Teuchos::rcp( new SVQBOrthoManager<ScalarType,MV,OP>(problem_->getM()) );
00333 
00335   // Parameter list
00336   Teuchos::ParameterList plist;
00337   plist.set("Block Size",blockSize_);
00338   plist.set("Full Ortho",fullOrtho_);
00339 
00340   // utils
00341   SolverUtils<ScalarType,MV,OP> msutils;
00342 
00344   // LOBPCG solver
00345   Teuchos::RCP<LOBPCG<ScalarType,MV,OP> > lobpcg_solver 
00346     = Teuchos::rcp( new LOBPCG<ScalarType,MV,OP>(problem_,sorter,printer,outputtest,ortho,plist) );
00347   // set any auxiliary vectors defined in the problem
00348   Teuchos::RCP< const MV > probauxvecs = problem_->getAuxVecs();
00349   if (probauxvecs != Teuchos::null) {
00350     lobpcg_solver->setAuxVecs( Teuchos::tuple< Teuchos::RCP<const MV> >(probauxvecs) );
00351   }
00352 
00354   // Storage
00355   // 
00356   // lockvecs will contain eigenvectors that have been determined "locked" by the status test
00357   int numlocked = 0;
00358   Teuchos::RCP<MV> lockvecs;
00359   if (useLocking_) {
00360     lockvecs = MVT::Clone(*problem_->getInitVec(),maxLocked_);
00361   }
00362   std::vector<MagnitudeType> lockvals;
00363   // workMV will be used as work space for LOBPCGRitzFailure recovery and locking
00364   // it will be partitioned in these cases as follows:
00365   // for LOBPCGRitzFailure recovery:
00366   // workMV = [X H P OpX OpH OpP], where OpX OpH OpP will be used for K and M
00367   // total size: 2*3*blocksize
00368   // for locking
00369   // workMV = [X P MX MP], with MX,MP needing storage only if hasM==true
00370   // total size: 2*blocksize or 4*blocksize
00371   Teuchos::RCP<MV> workMV;
00372   if (fullOrtho_ == false && recover_ == true) {
00373     workMV = MVT::Clone(*problem_->getInitVec(),2*3*blockSize_);
00374   }
00375   else if (useLocking_) {
00376     if (problem_->getM() != Teuchos::null) {
00377       workMV = MVT::Clone(*problem_->getInitVec(),4*blockSize_);
00378     }
00379     else {
00380       workMV = MVT::Clone(*problem_->getInitVec(),2*blockSize_);
00381     }
00382   }
00383 
00384   // initialize the solution to nothing in case we throw an exception
00385   Eigensolution<ScalarType,MV> sol;
00386   sol.numVecs = 0;
00387   problem_->setSolution(sol);
00388 
00389   // initialize the solver if the user specified a state
00390   if (state_ != Teuchos::null) {
00391     lobpcg_solver->initialize(*state_);
00392   }
00393 
00394   // tell the lobpcg_solver to iterate
00395   while (1) {
00396     try {
00397       lobpcg_solver->iterate();
00398 
00399       // check convergence first
00400       if (convtest->getStatus() == Passed || (maxtest != Teuchos::null && maxtest->getStatus() == Passed) ) {
00401         // we have convergence or not
00402         // convtest->whichVecs() tells us which vectors from lockvecs and solver->getRitzVectors() are the ones we want
00403         // convtest->howMany() will tell us how many
00404         break;
00405       }
00406       // check locking if we didn't converge
00407       else if (locktest != Teuchos::null && locktest->getStatus() == Passed) {
00408 
00409         // remove the locked vectors,values from lobpcg_solver: put them in newvecs, newvals
00410         int numnew = locktest->howMany();
00411         TEST_FOR_EXCEPTION(numnew <= 0,std::logic_error,"Anasazi::LOBPCGSolMgr::solve(): status test mistake.");
00412         // get the indices
00413         std::vector<int> indnew = locktest->whichVecs();
00414 
00415         // don't lock more than maxLocked_; we didn't allocate enough space.
00416         if (numlocked + numnew > maxLocked_) {
00417           numnew = maxLocked_ - numlocked;
00418           indnew.resize(numnew);
00419         }
00420 
00421         // the call below to lobpcg_solver->setAuxVecs() will reset the solver to unitialized with hasP() == false
00422         // store the hasP() state for use below
00423         bool hadP = lobpcg_solver->hasP();
00424 
00425         {
00426           // debug printing
00427           printer->print(Debug,"Locking vectors: ");
00428           for (unsigned int i=0; i<indnew.size(); i++) {printer->stream(Debug) << " " << indnew[i];}
00429           printer->print(Debug,"\n");
00430         }
00431         std::vector<MagnitudeType> newvals(numnew);
00432         Teuchos::RCP<const MV> newvecs;
00433         {
00434           // work in a local scope, to hide the variabes needed for extracting this info
00435           // get the vectors
00436           newvecs = MVT::CloneView(*lobpcg_solver->getRitzVectors(),indnew);
00437           // get the values
00438           std::vector<Value<ScalarType> > allvals = lobpcg_solver->getRitzValues();
00439           for (int i=0; i<numnew; i++) {
00440             newvals[i] = allvals[indnew[i]].realpart;
00441           }
00442         }
00443         // put newvecs into lockvecs
00444         {
00445           std::vector<int> indlock(numnew);
00446           for (int i=0; i<numnew; i++) indlock[i] = numlocked+i;
00447           MVT::SetBlock(*newvecs,indlock,*lockvecs);
00448           newvecs = Teuchos::null;
00449         }
00450         // put newvals into lockvals
00451         lockvals.insert(lockvals.end(),newvals.begin(),newvals.end());
00452         numlocked += numnew;
00453         // add locked vecs as aux vecs, along with aux vecs from problem
00454         {
00455           std::vector<int> indlock(numlocked);
00456           for (int i=0; i<numlocked; i++) indlock[i] = i;
00457           Teuchos::RCP<const MV> curlocked = MVT::CloneView(*lockvecs,indlock);
00458           if (probauxvecs != Teuchos::null) {
00459             lobpcg_solver->setAuxVecs( Teuchos::tuple< Teuchos::RCP<const MV> >(probauxvecs,curlocked) );
00460           }
00461           else {
00462             lobpcg_solver->setAuxVecs( Teuchos::tuple< Teuchos::RCP<const MV> >(curlocked) );
00463           }
00464         }
00465         // add locked vals to convtest
00466         convtest->setAuxVals(lockvals);
00467         // fill out the empty state in the solver
00468         {
00469           LOBPCGState<ScalarType,MV> state = lobpcg_solver->getState();
00470           Teuchos::RCP<MV> newstateX, newstateMX, newstateP, newstateMP;
00471           //
00472           // workMV will be partitioned as follows: workMV = [X P MX MP], 
00473           //
00474           // make a copy of the current X,MX state
00475           std::vector<int> bsind(blockSize_); 
00476           for (int i=0; i<blockSize_; i++) bsind[i] = i;
00477           newstateX = MVT::CloneView(*workMV,bsind);
00478           MVT::SetBlock(*state.X,bsind,*newstateX);
00479 
00480           if (state.MX != Teuchos::null) {
00481             std::vector<int> block3(blockSize_);
00482             for (int i=0; i<blockSize_; i++) block3[i] = 2*blockSize_+i;
00483             newstateMX = MVT::CloneView(*workMV,block3);
00484             MVT::SetBlock(*state.MX,bsind,*newstateMX);
00485           }
00486           //
00487           // get select part, set to random, apply M
00488           {
00489             Teuchos::RCP<MV> newX = MVT::CloneView(*newstateX,indnew);
00490             MVT::MvRandom(*newX);
00491 
00492             if (newstateMX != Teuchos::null) {
00493               Teuchos::RCP<MV> newMX = MVT::CloneView(*newstateMX,indnew);
00494               OPT::Apply(*problem_->getM(),*newX,*newMX);
00495             }
00496           }
00497 
00498           Teuchos::Array<Teuchos::RCP<const MV> > curauxvecs = lobpcg_solver->getAuxVecs();
00499           Teuchos::Array<Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > > dummy;
00500           // ortho X against the aux vectors
00501           ortho->projectAndNormalizeMat(*newstateX,newstateMX,dummy,Teuchos::null,curauxvecs);
00502 
00503           if (hadP) {
00504             //
00505             // get P and optionally MP, orthogonalize against X and auxiliary vectors
00506             std::vector<int> block2(blockSize_);
00507             for (int i=0; i<blockSize_; i++) block2[i] = blockSize_+i;
00508             newstateP = MVT::CloneView(*workMV,block2);
00509             MVT::SetBlock(*state.P,bsind,*newstateP);
00510 
00511             if (state.MP != Teuchos::null) {
00512               std::vector<int> block4(blockSize_);
00513               for (int i=0; i<blockSize_; i++) block4[i] = 3*blockSize_+i;
00514               newstateMP = MVT::CloneView(*workMV,block4);
00515               MVT::SetBlock(*state.MP,bsind,*newstateMP);
00516             }
00517 
00518             if (fullOrtho_) {
00519               // ortho P against the new aux vectors and new X
00520               curauxvecs.push_back(newstateX);
00521               ortho->projectAndNormalizeMat(*newstateP,newstateMP,dummy,Teuchos::null,curauxvecs);
00522             }
00523             else {
00524               // ortho P against the new aux vectors
00525               ortho->projectAndNormalizeMat(*newstateP,newstateMP,dummy,Teuchos::null,curauxvecs);
00526             }
00527           }
00528           // set the new state
00529           LOBPCGState<ScalarType,MV> newstate;
00530           newstate.X  = newstateX;
00531           newstate.MX = newstateMX;
00532           newstate.P  = newstateP;
00533           newstate.MP = newstateMP;
00534           lobpcg_solver->initialize(newstate);
00535         }
00536 
00537         if (numlocked == maxLocked_) {
00538           // disabled locking now
00539           locktest->setQuorum(blockSize_+1);
00540         }
00541       }
00542       else {
00543         TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::LOBPCGSolMgr::solve(): Invalid return from lobpcg_solver::iterate().");
00544       }
00545     }
00546     catch (LOBPCGRitzFailure re) {
00547       if (fullOrtho_==true || recover_==false) {
00548         // if we are already using full orthogonalization, there isn't much we can do here. 
00549         // the most recent information in the status tests is still valid, and can be used to extract/return the 
00550         // eigenpairs that have converged.
00551         printer->stream(Warnings) << "Error! Caught LOBPCGRitzFailure at iteration " << lobpcg_solver->getNumIters() << std::endl
00552                                 << "Will not try to recover." << std::endl;
00553         break; // while(1)
00554       }
00555       printer->stream(Warnings) << "Error! Caught LOBPCGRitzFailure at iteration " << lobpcg_solver->getNumIters() << std::endl
00556                               << "Full orthogonalization is off; will try to recover." << std::endl;
00557       // get the current "basis" from the solver, orthonormalize it, do a rayleigh-ritz, and restart with the ritz vectors
00558       // if there aren't enough, break and quit with what we have
00559       //
00560       // workMV = [X H P OpX OpH OpP], where OpX OpH OpP will be used for K and M
00561       LOBPCGState<ScalarType,MV> curstate = lobpcg_solver->getState();
00562       Teuchos::RCP<MV> restart, Krestart, Mrestart;
00563       int localsize = lobpcg_solver->hasP() ? 3*blockSize_ : 2*blockSize_;
00564       bool hasM = problem_->getM() != Teuchos::null;
00565       {
00566         std::vector<int> recind(localsize);
00567         for (int i=0; i<localsize; i++) recind[i] = i;
00568         restart = MVT::CloneView(*workMV,recind);
00569       }
00570       {
00571         std::vector<int> recind(localsize);
00572         for (int i=0; i<localsize; i++) recind[i] = localsize+i;
00573         Krestart = MVT::CloneView(*workMV,recind);
00574       }
00575       if (hasM) {
00576         Mrestart = Krestart;
00577       }
00578       else {
00579         Mrestart = restart;
00580       }
00581       //
00582       // set restart = [X H P] and Mrestart = M*[X H P]
00583       //
00584       // put X into [0 , blockSize)
00585       {
00586         std::vector<int> blk1(blockSize_);
00587         for (int i=0; i < blockSize_; i++) blk1[i] = i;
00588         MVT::SetBlock(*curstate.X,blk1,*restart);
00589 
00590         // put MX into [0 , blockSize)
00591         if (hasM) {
00592           MVT::SetBlock(*curstate.MX,blk1,*Mrestart);
00593         }
00594       }
00595       //
00596       // put H into [blockSize_ , 2*blockSize)
00597       {
00598         std::vector<int> blk2(blockSize_);
00599         for (int i=0; i < blockSize_; i++) blk2[i] = blockSize_+i;
00600         MVT::SetBlock(*curstate.H,blk2,*restart);
00601 
00602         // put MH into [blockSize_ , 2*blockSize)
00603         if (hasM) {
00604           MVT::SetBlock(*curstate.MH,blk2,*Mrestart);
00605         }
00606       }
00607       // optionally, put P into [2*blockSize,3*blockSize)
00608       if (localsize == 3*blockSize_) {
00609         std::vector<int> blk3(blockSize_);
00610         for (int i=0; i < blockSize_; i++) blk3[i] = 2*blockSize_+i;
00611         MVT::SetBlock(*curstate.P,blk3,*restart);
00612 
00613         // put MP into [2*blockSize,3*blockSize)
00614         if (hasM) {
00615           MVT::SetBlock(*curstate.MP,blk3,*Mrestart);
00616         }
00617       }
00618       // project against auxvecs and locked vecs, and orthonormalize the basis
00619       Teuchos::Array<Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > > dummy;
00620       Teuchos::Array<Teuchos::RCP<const MV> > Q;
00621       {
00622         if (numlocked > 0) {
00623           std::vector<int> indlock(numlocked);
00624           for (int i=0; i<numlocked; i++) indlock[i] = i;
00625           Teuchos::RCP<const MV> curlocked = MVT::CloneView(*lockvecs,indlock);
00626           Q.push_back(curlocked);
00627         }
00628         if (probauxvecs != Teuchos::null) {
00629           Q.push_back(probauxvecs);
00630         }
00631       }
00632       int rank = ortho->projectAndNormalizeMat(*restart,Mrestart,dummy,Teuchos::null,Q);
00633       if (rank < blockSize_) {
00634         // quit
00635         printer->stream(Errors) << "Error! Recovered basis only rank " << rank << ". Block size is " << blockSize_ << ".\n"
00636                                 << "Recovery failed." << std::endl;
00637         break;
00638       }
00639       // reduce multivec size if necessary
00640       if (rank < localsize) {
00641         localsize = rank;
00642         std::vector<int> redind(localsize);
00643         for (int i=0; i<localsize; i++) redind[i] = i;
00644         // grab the first part of restart,Krestart
00645         restart = MVT::CloneView(*restart,redind);
00646         Krestart = MVT::CloneView(*Krestart,redind);
00647         if (hasM) {
00648           Mrestart = Krestart;
00649         }
00650         else {
00651           Mrestart = restart;
00652         }
00653       }
00654       Teuchos::SerialDenseMatrix<int,ScalarType> KK(localsize,localsize), MM(localsize,localsize), S(localsize,localsize);
00655       std::vector<MagnitudeType> theta(localsize);
00656       // project the matrices
00657       //
00658       // MM = restart^H M restart
00659       MVT::MvTransMv(1.0,*restart,*Mrestart,MM);
00660       // 
00661       // compute Krestart = K*restart
00662       OPT::Apply(*problem_->getOperator(),*restart,*Krestart);
00663       //
00664       // KK = restart^H K restart
00665       MVT::MvTransMv(1.0,*restart,*Krestart,KK);
00666       rank = localsize;
00667       msutils.directSolver(localsize,KK,Teuchos::rcp(&MM,false),S,theta,rank,1);
00668       if (rank < blockSize_) {
00669         printer->stream(Errors) << "Error! Recovered basis of rank " << rank << " produced only " << rank << "ritz vectors.\n"
00670                                 << "Block size is " << blockSize_ << ".\n"
00671                                 << "Recovery failed." << std::endl;
00672         break;
00673       }
00674       theta.resize(rank);
00675       //
00676       // sort the ritz values using the sort manager
00677       {
00678         Teuchos::BLAS<int,ScalarType> blas;
00679         std::vector<int> order(rank);
00680         // sort
00681         sorter->sort( lobpcg_solver.get(), rank, theta, &order );   // don't catch exception
00682         // Sort the primitive ritz vectors
00683         Teuchos::SerialDenseMatrix<int,ScalarType> curS(Teuchos::View,S,rank,rank);
00684         msutils.permuteVectors(order,curS);
00685       }
00686       //
00687       Teuchos::SerialDenseMatrix<int,ScalarType> S1(Teuchos::View,S,localsize,blockSize_);
00688       //
00689       // compute the ritz vectors: store them in Krestart
00690       LOBPCGState<ScalarType,MV> newstate;
00691       Teuchos::RCP<MV> newX; 
00692       {
00693         std::vector<int> bsind(blockSize_);
00694         for (int i=0; i<blockSize_; i++) bsind[i] = i;
00695         newX = MVT::CloneView(*Krestart,bsind);
00696       }
00697       MVT::MvTimesMatAddMv(1.0,*restart,S1,0.0,*newX);
00698       // send X and theta into the solver
00699       newstate.X = newX;
00700       theta.resize(blockSize_);
00701       newstate.T = Teuchos::rcp( &theta, false );
00702       // initialize
00703       lobpcg_solver->initialize(newstate);
00704     }
00705     // don't catch any other exceptions
00706   }
00707 
00708   sol.numVecs = convtest->howMany();
00709   if (sol.numVecs > 0) {
00710     sol.Evecs = MVT::Clone(*problem_->getInitVec(),sol.numVecs);
00711     sol.Espace = sol.Evecs;
00712     sol.Evals.resize(sol.numVecs);
00713     std::vector<MagnitudeType> vals(sol.numVecs);
00714 
00715     // copy them into the solution
00716     std::vector<int> which = convtest->whichVecs();
00717     // indices between [0,blockSize) refer to vectors/values in the solver
00718     // indices between [blockSize,blocksize+numlocked) refer to locked vectors/values
00719     // everything has already been ordered by the solver; we just have to partition the two references
00720     std::vector<int> inlocked(0), insolver(0);
00721     for (unsigned int i=0; i<which.size(); i++) {
00722       if (which[i] < blockSize_) {
00723         insolver.push_back(which[i]);
00724       }
00725       else {
00726         // sanity check
00727         TEST_FOR_EXCEPTION(which[i] >= numlocked+blockSize_,std::logic_error,"Anasazi::LOBPCGSolMgr::solve(): indexing mistake.");
00728         inlocked.push_back(which[i] - blockSize_);
00729       }
00730     }
00731 
00732     TEST_FOR_EXCEPTION(insolver.size() + inlocked.size() != (unsigned int)sol.numVecs,std::logic_error,"Anasazi::LOBPCGSolMgr::solve(): indexing mistake.");
00733 
00734     // set the vecs,vals in the solution
00735     if (insolver.size() > 0) {
00736       // set vecs
00737       int lclnum = insolver.size();
00738       std::vector<int> tosol(lclnum);
00739       for (int i=0; i<lclnum; i++) tosol[i] = i;
00740       Teuchos::RCP<const MV> v = MVT::CloneView(*lobpcg_solver->getRitzVectors(),insolver);
00741       MVT::SetBlock(*v,tosol,*sol.Evecs);
00742       // set vals
00743       std::vector<Value<ScalarType> > fromsolver = lobpcg_solver->getRitzValues();
00744       for (unsigned int i=0; i<insolver.size(); i++) {
00745         vals[i] = fromsolver[insolver[i]].realpart;
00746       }
00747     }
00748 
00749     // get the vecs,vals from locked storage
00750     if (inlocked.size() > 0) {
00751       int solnum = insolver.size();
00752       // set vecs
00753       int lclnum = inlocked.size();
00754       std::vector<int> tosol(lclnum);
00755       for (int i=0; i<lclnum; i++) tosol[i] = solnum + i;
00756       Teuchos::RCP<const MV> v = MVT::CloneView(*lockvecs,inlocked);
00757       MVT::SetBlock(*v,tosol,*sol.Evecs);
00758       // set vals
00759       for (unsigned int i=0; i<inlocked.size(); i++) {
00760         vals[i+solnum] = lockvals[inlocked[i]];
00761       }
00762     }
00763 
00764     // sort the eigenvalues and permute the eigenvectors appropriately
00765     {
00766       std::vector<int> order(sol.numVecs);
00767       sorter->sort( lobpcg_solver.get(), sol.numVecs, vals, &order );
00768       // store the values in the Eigensolution
00769       for (int i=0; i<sol.numVecs; i++) {
00770         sol.Evals[i].realpart = vals[i];
00771         sol.Evals[i].imagpart = MT::zero();
00772       }
00773       // now permute the eigenvectors according to order
00774       msutils.permuteVectors(sol.numVecs,order,*sol.Evecs);
00775     }
00776 
00777     // setup sol.index, remembering that all eigenvalues are real so that index = {0,...,0}
00778     sol.index.resize(sol.numVecs,0);
00779   }
00780 
00781   // print final summary
00782   lobpcg_solver->currentStatus(printer->stream(FinalSummary));
00783 
00784   // print timing information
00785   Teuchos::TimeMonitor::summarize(printer->stream(TimingDetails));
00786 
00787   problem_->setSolution(sol);
00788   printer->stream(Debug) << "Returning " << sol.numVecs << " eigenpairs to eigenproblem." << std::endl;
00789 
00790   if (sol.numVecs < nev) return Unconverged; // return from LOBPCGSolMgr::solve() 
00791   return Converged; // return from LOBPCGSolMgr::solve() 
00792 }
00793 
00794 
00795 } // end Anasazi namespace
00796 
00797 #endif /* ANASAZI_LOBPCG_SOLMGR_HPP */

Generated on Tue Oct 20 12:45:18 2009 for Anasazi by doxygen 1.4.7