AnasaziBlockKrylovSchurSolMgr.hpp

Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                 Anasazi: Block Eigensolvers Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00025 //
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 #ifndef ANASAZI_BLOCK_KRYLOV_SCHUR_SOLMGR_HPP
00030 #define ANASAZI_BLOCK_KRYLOV_SCHUR_SOLMGR_HPP
00031 
00036 #include "AnasaziConfigDefs.hpp"
00037 #include "AnasaziTypes.hpp"
00038 
00039 #include "AnasaziEigenproblem.hpp"
00040 #include "AnasaziSolverManager.hpp"
00041 
00042 #include "AnasaziBlockKrylovSchur.hpp"
00043 #include "AnasaziBasicSort.hpp"
00044 #include "AnasaziSVQBOrthoManager.hpp"
00045 #include "AnasaziBasicOrthoManager.hpp"
00046 #include "AnasaziStatusTestMaxIters.hpp"
00047 #include "AnasaziStatusTestResNorm.hpp"
00048 #include "AnasaziStatusTestOrderedResNorm.hpp"
00049 #include "AnasaziStatusTestCombo.hpp"
00050 #include "AnasaziStatusTestOutput.hpp"
00051 #include "AnasaziBasicOutputManager.hpp"
00052 #include "AnasaziSolverUtils.hpp"
00053 #include "Teuchos_BLAS.hpp"
00054 #include "Teuchos_LAPACK.hpp"
00055 #include "Teuchos_TimeMonitor.hpp"
00056 
00070 namespace Anasazi {
00071 
00072 template<class ScalarType, class MV, class OP>
00073 class BlockKrylovSchurSolMgr : public SolverManager<ScalarType,MV,OP> {
00074 
00075   private:
00076     typedef MultiVecTraits<ScalarType,MV> MVT;
00077     typedef OperatorTraits<ScalarType,MV,OP> OPT;
00078     typedef Teuchos::ScalarTraits<ScalarType> SCT;
00079     typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
00080     typedef Teuchos::ScalarTraits<MagnitudeType> MT;
00081     
00082   public:
00083 
00085 
00086 
00102   BlockKrylovSchurSolMgr( const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
00103                              Teuchos::ParameterList &pl );
00104 
00106   virtual ~BlockKrylovSchurSolMgr() {};
00108   
00110 
00111 
00112   const Eigenproblem<ScalarType,MV,OP>& getProblem() const {
00113     return *_problem;
00114   }
00115 
00118   std::vector<Value<ScalarType> > getRitzValues() const {
00119     std::vector<Value<ScalarType> > ret( _ritzValues );
00120     return ret;
00121   }
00122 
00129    Teuchos::Array<Teuchos::RCP<Teuchos::Time> > getTimers() const {
00130      return tuple(_timerSolve, _timerRestarting);
00131    }
00132 
00134 
00136 
00137     
00156   ReturnType solve();
00158 
00159   private:
00160   Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > _problem;
00161   Teuchos::RCP<SortManager<ScalarType,MV,OP> > _sort;
00162 
00163   std::string _whch, _ortho; 
00164   MagnitudeType _ortho_kappa;
00165 
00166   MagnitudeType _convtol;
00167   int _maxRestarts;
00168   bool _relconvtol,_conjSplit;
00169   int _blockSize, _numBlocks, _stepSize, _nevBlocks, _xtra_nevBlocks;
00170   int _verbosity;
00171   bool _inSituRestart;
00172 
00173   std::vector<Value<ScalarType> > _ritzValues;
00174 
00175   Teuchos::RCP<Teuchos::Time> _timerSolve, _timerRestarting;
00176 
00177 };
00178 
00179 
00180 // Constructor
00181 template<class ScalarType, class MV, class OP>
00182 BlockKrylovSchurSolMgr<ScalarType,MV,OP>::BlockKrylovSchurSolMgr( 
00183         const Teuchos::RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
00184         Teuchos::ParameterList &pl ) : 
00185   _problem(problem),
00186   _whch("LM"),
00187   _ortho("SVQB"),
00188   _ortho_kappa(-1.0),
00189   _convtol(0),
00190   _maxRestarts(20),
00191   _relconvtol(true),
00192   _conjSplit(false),
00193   _blockSize(0),
00194   _numBlocks(0),
00195   _stepSize(0),
00196   _nevBlocks(0),
00197   _xtra_nevBlocks(0),
00198   _verbosity(Anasazi::Errors),
00199   _inSituRestart(false),
00200   _timerSolve(Teuchos::TimeMonitor::getNewTimer("BKSSolMgr::solve()")),
00201   _timerRestarting(Teuchos::TimeMonitor::getNewTimer("BKSSolMgr restarting"))
00202 {
00203   TEST_FOR_EXCEPTION(_problem == Teuchos::null,               std::invalid_argument, "Problem not given to solver manager.");
00204   TEST_FOR_EXCEPTION(!_problem->isProblemSet(),               std::invalid_argument, "Problem not set.");
00205   TEST_FOR_EXCEPTION(_problem->getInitVec() == Teuchos::null, std::invalid_argument, "Problem does not contain initial vectors to clone from.");
00206 
00207   const int nev = _problem->getNEV();
00208 
00209   // convergence tolerance
00210   _convtol = pl.get("Convergence Tolerance",MT::prec());
00211   _relconvtol = pl.get("Relative Convergence Tolerance",_relconvtol);
00212   
00213   // maximum number of restarts
00214   _maxRestarts = pl.get("Maximum Restarts",_maxRestarts);
00215 
00216   // block size: default is 1
00217   _blockSize = pl.get("Block Size",1);
00218   TEST_FOR_EXCEPTION(_blockSize <= 0, std::invalid_argument,
00219                      "Anasazi::BlockKrylovSchurSolMgr: \"Block Size\" must be strictly positive.");
00220 
00221   // set the number of blocks we need to save to compute the nev eigenvalues of interest.
00222   _xtra_nevBlocks = pl.get("Extra NEV Blocks",0);
00223   if (nev%_blockSize) {
00224     _nevBlocks = nev/_blockSize + _xtra_nevBlocks + 1;
00225   } else {
00226     _nevBlocks = nev/_blockSize + _xtra_nevBlocks;
00227   }
00228 
00229   _numBlocks = pl.get("Num Blocks",3*_nevBlocks);
00230   TEST_FOR_EXCEPTION(_numBlocks <= _nevBlocks, std::invalid_argument,
00231                      "Anasazi::BlockKrylovSchurSolMgr: \"Num Blocks\" must be strictly positive and large enough to compute the requested eigenvalues.");
00232 
00233   TEST_FOR_EXCEPTION(_numBlocks*_blockSize > MVT::GetVecLength(*_problem->getInitVec()),
00234                      std::invalid_argument,
00235                      "Anasazi::BlockKrylovSchurSolMgr: Potentially impossible orthogonality requests. Reduce basis size.");
00236   
00237   // step size: the default is _maxRestarts*_numBlocks, so that Ritz values are only computed every restart.
00238   if (_maxRestarts) {
00239     _stepSize = pl.get("Step Size", (_maxRestarts+1)*(_numBlocks+1));
00240   } else {
00241     _stepSize = pl.get("Step Size", _numBlocks+1);
00242   }
00243   TEST_FOR_EXCEPTION(_stepSize < 1, std::invalid_argument,
00244                      "Anasazi::BlockKrylovSchurSolMgr: \"Step Size\" must be strictly positive.");
00245 
00246   // get the sort manager
00247   if (pl.isParameter("Sort Manager")) {
00248     _sort = Teuchos::getParameter<Teuchos::RCP<Anasazi::SortManager<ScalarType,MV,OP> > >(pl,"Sort Manager");
00249   } else {
00250     // which values to solve for
00251     _whch = pl.get("Which",_whch);
00252     TEST_FOR_EXCEPTION(_whch != "SM" && _whch != "LM" && _whch != "SR" && _whch != "LR" && _whch != "SI" && _whch != "LI",
00253                        std::invalid_argument, "Invalid sorting string.");
00254     _sort = Teuchos::rcp( new BasicSort<ScalarType,MV,OP>(_whch) );
00255   }
00256 
00257   // which orthogonalization to use
00258   _ortho = pl.get("Orthogonalization",_ortho);
00259   if (_ortho != "DGKS" && _ortho != "SVQB") {
00260     _ortho = "SVQB";
00261   }
00262 
00263   // which orthogonalization constant to use
00264   _ortho_kappa = pl.get("Orthogonalization Constant",_ortho_kappa);
00265 
00266   // verbosity level
00267   if (pl.isParameter("Verbosity")) {
00268     if (Teuchos::isParameterType<int>(pl,"Verbosity")) {
00269       _verbosity = pl.get("Verbosity", _verbosity);
00270     } else {
00271       _verbosity = (int)Teuchos::getParameter<Anasazi::MsgType>(pl,"Verbosity");
00272     }
00273   }
00274 
00275   // restarting technique: V*Q or applyHouse(V,H,tau)
00276   if (pl.isParameter("In Situ Restarting")) {
00277     if (Teuchos::isParameterType<bool>(pl,"In Situ Restarting")) {
00278       _inSituRestart = pl.get("In Situ Restarting",_inSituRestart);
00279     } else {
00280       _inSituRestart = (bool)Teuchos::getParameter<int>(pl,"In Situ Restarting");
00281     }
00282   }
00283 }
00284 
00285 
00286 // solve()
00287 template<class ScalarType, class MV, class OP>
00288 ReturnType 
00289 BlockKrylovSchurSolMgr<ScalarType,MV,OP>::solve() {
00290 
00291   const int nev = _problem->getNEV();
00292   ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
00293   ScalarType zero = Teuchos::ScalarTraits<ScalarType>::zero();
00294 
00295   Teuchos::BLAS<int,ScalarType> blas;
00296   Teuchos::LAPACK<int,ScalarType> lapack;
00297   typedef SolverUtils<ScalarType,MV,OP> msutils;
00298 
00300   // Output manager
00301   Teuchos::RCP<BasicOutputManager<ScalarType> > printer = Teuchos::rcp( new BasicOutputManager<ScalarType>(_verbosity) );
00302 
00304   // Status tests
00305   //
00306   // convergence
00307   Teuchos::RCP<StatusTestOrderedResNorm<ScalarType,MV,OP> > convtest 
00308     = Teuchos::rcp( new StatusTestOrderedResNorm<ScalarType,MV,OP>(_sort,_convtol,nev,StatusTestOrderedResNorm<ScalarType,MV,OP>::RITZRES_2NORM,_relconvtol) );
00309 
00310   // printing StatusTest
00311   Teuchos::RCP<StatusTestOutput<ScalarType,MV,OP> > outputtest
00312     = Teuchos::rcp( new StatusTestOutput<ScalarType,MV,OP>( printer,convtest,1,Passed ) );
00313 
00315   // Orthomanager
00316   //
00317   Teuchos::RCP<OrthoManager<ScalarType,MV> > ortho; 
00318   if (_ortho=="SVQB") {
00319     ortho = Teuchos::rcp( new SVQBOrthoManager<ScalarType,MV,OP>(_problem->getM()) );
00320   } else if (_ortho=="DGKS") {
00321     if (_ortho_kappa <= 0) {
00322       ortho = Teuchos::rcp( new BasicOrthoManager<ScalarType,MV,OP>(_problem->getM()) );
00323     }
00324     else {
00325       ortho = Teuchos::rcp( new BasicOrthoManager<ScalarType,MV,OP>(_problem->getM(),_ortho_kappa) );
00326     }
00327   } else {
00328     TEST_FOR_EXCEPTION(_ortho!="SVQB"&&_ortho!="DGKS",std::logic_error,"Anasazi::BlockKrylovSchurSolMgr::solve(): Invalid orthogonalization type.");
00329   }
00330   
00332   // Parameter list
00333   Teuchos::ParameterList plist;
00334   plist.set("Block Size",_blockSize);
00335   plist.set("Num Blocks",_numBlocks);
00336   plist.set("Step Size",_stepSize);
00337   plist.set("Print Number of Ritz Values",_nevBlocks*_blockSize);
00338 
00340   // BlockKrylovSchur solver
00341   Teuchos::RCP<BlockKrylovSchur<ScalarType,MV,OP> > bks_solver 
00342     = Teuchos::rcp( new BlockKrylovSchur<ScalarType,MV,OP>(_problem,_sort,printer,outputtest,ortho,plist) );
00343   // set any auxiliary vectors defined in the problem
00344   Teuchos::RCP< const MV > probauxvecs = _problem->getAuxVecs();
00345   if (probauxvecs != Teuchos::null) {
00346     bks_solver->setAuxVecs( Teuchos::tuple< Teuchos::RCP<const MV> >(probauxvecs) );
00347   }
00348 
00349   // Create workspace for the Krylov basis generated during a restart
00350   // Need at most (_nevBlocks*_blockSize+1) for the updated factorization and another block for the current factorization residual block (F).
00351   //  ---> (_nevBlocks*_blockSize+1) + _blockSize
00352   // If Hermitian, this becomes _nevBlocks*_blockSize + _blockSize
00353   // we only need this if there is the possibility of restarting, ex situ
00354   Teuchos::RCP<MV> workMV;
00355   if (_maxRestarts > 0) {
00356     if (_inSituRestart==true) {
00357       // still need one work vector for applyHouse()
00358       workMV = MVT::Clone( *_problem->getInitVec(), 1 );
00359     }
00360     else { // inSituRestart == false
00361       if (_problem->isHermitian()) {
00362         workMV = MVT::Clone( *_problem->getInitVec(), _nevBlocks*_blockSize + _blockSize );
00363       } else {
00364         workMV = MVT::Clone( *_problem->getInitVec(), _nevBlocks*_blockSize+1 + _blockSize );
00365       }
00366     }
00367   } else {
00368     workMV = Teuchos::null;
00369   }
00370 
00371   // go ahead and initialize the solution to nothing in case we throw an exception
00372   Eigensolution<ScalarType,MV> sol;
00373   sol.numVecs = 0;
00374   _problem->setSolution(sol);
00375 
00376   int numRestarts = 0;
00377   int cur_nevBlocks = 0;
00378 
00379   // enter solve() iterations
00380   {
00381     Teuchos::TimeMonitor slvtimer(*_timerSolve);
00382   
00383     // tell bks_solver to iterate
00384     while (1) {
00385       try {
00386         bks_solver->iterate();
00387     
00389         //
00390         // check convergence first
00391         //
00393         if (convtest->getStatus() == Passed ) {
00394           // we have convergence
00395           // convtest->whichVecs() tells us which vectors from solver state are the ones we want
00396           // convtest->howMany() will tell us how many
00397           break;
00398         }
00400         //
00401         // check for restarting, i.e. the subspace is full
00402         //
00404         // this is for the Hermitian case, or non-Hermitian conjugate split situation.
00405         // --> for the Hermitian case the current subspace dimension needs to match the maximum subspace dimension
00406         // --> for the non-Hermitian case:
00407         //     --> if a conjugate pair was detected in the previous restart then the current subspace dimension needs to match the
00408         //         maximum subspace dimension (the BKS solver keeps one extra vector if the problem is non-Hermitian).
00409         //     --> if a conjugate pair was not detected in the previous restart then the current subspace dimension will be one less
00410         //         than the maximum subspace dimension.
00411         else if ( (bks_solver->getCurSubspaceDim() == bks_solver->getMaxSubspaceDim()) ||
00412                   (!_problem->isHermitian() && !_conjSplit && (bks_solver->getCurSubspaceDim()+1 == bks_solver->getMaxSubspaceDim())) ) {
00413   
00414           Teuchos::TimeMonitor restimer(*_timerRestarting);
00415   
00416           if ( numRestarts >= _maxRestarts ) {
00417             break; // break from while(1){bks_solver->iterate()}
00418           }
00419           numRestarts++;
00420   
00421           printer->stream(Debug) << " Performing restart number " << numRestarts << " of " << _maxRestarts << std::endl << std::endl;
00422   
00423           // Update the Schur form of the projected eigenproblem, then sort it.
00424           if (!bks_solver->isSchurCurrent())
00425             bks_solver->computeSchurForm( true );
00426 
00427           // Get the most current Ritz values before we continue.
00428           _ritzValues = bks_solver->getRitzValues();
00429 
00430           // Get the state.
00431           BlockKrylovSchurState<ScalarType,MV> oldState = bks_solver->getState();
00432 
00433           // Get the current dimension of the factorization
00434           int curDim = oldState.curDim;
00435 
00436           // Determine if the storage for the nev eigenvalues of interest splits a complex conjugate pair.
00437           std::vector<int> ritzIndex = bks_solver->getRitzIndex();
00438           if (ritzIndex[_nevBlocks*_blockSize-1]==1) {
00439             _conjSplit = true;
00440             cur_nevBlocks = _nevBlocks*_blockSize+1;
00441           } else {
00442             _conjSplit = false;
00443             cur_nevBlocks = _nevBlocks*_blockSize;
00444           }
00445 
00446           // Update the Krylov-Schur decomposition
00447 
00448           // Get a view of the Schur vectors of interest.
00449           Teuchos::SerialDenseMatrix<int,ScalarType> Qnev(Teuchos::View, *(oldState.Q), curDim, cur_nevBlocks);
00450 
00451           // Get a view of the current Krylov basis.
00452           std::vector<int> curind( curDim );
00453           for (int i=0; i<curDim; i++) { curind[i] = i; }
00454           Teuchos::RCP<const MV> basistemp = MVT::CloneView( *(oldState.V), curind );
00455 
00456           // Compute the new Krylov basis: Vnew = V*Qnev
00457           // 
00458           // this will occur ex situ in workspace allocated for this purpose (tmpMV)
00459           // or in situ in the solver's memory space.
00460           //
00461           // we will also set a pointer for the location that the current factorization residual block (F),
00462           // currently located after the current basis in oldstate.V, will be moved to
00463           //
00464           Teuchos::RCP<MV> newF;
00465           if (_inSituRestart) {
00466             //
00467             // get non-const pointer to solver's basis so we can work in situ
00468             Teuchos::RCP<MV> solverbasis = Teuchos::rcp_const_cast<MV>(oldState.V);
00469             Teuchos::SerialDenseMatrix<int,ScalarType> copyQnev(Qnev);
00470             // 
00471             // perform Householder QR of copyQnev = Q [D;0], where D is unit diag. We will want D below.
00472             std::vector<ScalarType> tau(cur_nevBlocks), work(cur_nevBlocks);
00473             int info;
00474             lapack.GEQRF(curDim,cur_nevBlocks,copyQnev.values(),copyQnev.stride(),&tau[0],&work[0],work.size(),&info);
00475             TEST_FOR_EXCEPTION(info != 0,std::logic_error,
00476                                "Anasazi::BlockDavidsonSolMgr::solve(): error calling GEQRF during restarting.");
00477             // we need to get the diagonal of D
00478             std::vector<ScalarType> d(cur_nevBlocks);
00479             for (int j=0; j<copyQnev.numCols(); j++) {
00480               d[j] = copyQnev(j,j);
00481             }
00482             if (printer->isVerbosity(Debug)) {
00483               Teuchos::SerialDenseMatrix<int,ScalarType> R(Teuchos::Copy,copyQnev,cur_nevBlocks,cur_nevBlocks);
00484               for (int j=0; j<R.numCols(); j++) {
00485                 R(j,j) = SCT::magnitude(R(j,j)) - 1.0;
00486                 for (int i=j+1; i<R.numRows(); i++) {
00487                   R(i,j) = zero;
00488                 }
00489               }
00490               printer->stream(Debug) << "||Triangular factor of Su - I||: " << R.normFrobenius() << std::endl;
00491             }
00492             // 
00493             // perform implicit V*Qnev
00494             // this actually performs V*[Qnev Qtrunc*M] = [newV truncV], for some unitary M
00495             // we are interested in only the first cur_nevBlocks vectors of the result
00496             curind.resize(curDim);
00497             for (int i=0; i<curDim; i++) curind[i] = i;
00498             Teuchos::RCP<MV> oldV = MVT::CloneView(*solverbasis,curind);
00499             msutils::applyHouse(cur_nevBlocks,*oldV,copyQnev,tau,workMV);
00500             // clear pointer
00501             oldV = Teuchos::null;
00502             // multiply newV*D
00503             // get pointer to new basis
00504             curind.resize(cur_nevBlocks);
00505             for (int i=0; i<cur_nevBlocks; i++) { curind[i] = i; }
00506             oldV = MVT::CloneView( *solverbasis, curind );
00507             MVT::MvScale(*oldV,d);
00508             oldV = Teuchos::null;
00509             // get pointer to new location for F
00510             curind.resize(_blockSize);
00511             for (int i=0; i<_blockSize; i++) { curind[i] = cur_nevBlocks + i; }
00512             newF = MVT::CloneView( *solverbasis, curind );
00513           }
00514           else {
00515             // get pointer to first part of work space
00516             curind.resize(cur_nevBlocks);
00517             for (int i=0; i<cur_nevBlocks; i++) { curind[i] = i; }
00518             Teuchos::RCP<MV> tmp_newV = MVT::CloneView(*workMV, curind );
00519             // perform V*Qnev
00520             MVT::MvTimesMatAddMv( one, *basistemp, Qnev, zero, *tmp_newV );
00521             tmp_newV = Teuchos::null;
00522             // get pointer to new location for F
00523             curind.resize(_blockSize);
00524             for (int i=0; i<_blockSize; i++) { curind[i] = cur_nevBlocks + i; }
00525             newF = MVT::CloneView( *workMV, curind );
00526           }
00527 
00528           // Move the current factorization residual block (F) to the last block of newV.
00529           curind.resize(_blockSize);
00530           for (int i=0; i<_blockSize; i++) { curind[i] = curDim + i; }
00531           Teuchos::RCP<const MV> oldF = MVT::CloneView( *(oldState.V), curind );
00532           for (int i=0; i<_blockSize; i++) { curind[i] = i; }
00533           MVT::SetBlock( *oldF, curind, *newF );
00534           newF = Teuchos::null;
00535 
00536           // Update the Krylov-Schur quasi-triangular matrix.
00537           //
00538           // Create storage for the new Schur matrix of the Krylov-Schur factorization
00539           // Copy over the current quasi-triangular factorization of oldState.H which is stored in oldState.S.
00540           Teuchos::SerialDenseMatrix<int,ScalarType> oldS(Teuchos::View, *(oldState.S), cur_nevBlocks+_blockSize, cur_nevBlocks);
00541           Teuchos::RCP<Teuchos::SerialDenseMatrix<int,ScalarType> > newH = 
00542             Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>( oldS ) );
00543           //
00544           // Get a view of the B block of the current factorization
00545           Teuchos::SerialDenseMatrix<int,ScalarType> oldB(Teuchos::View, *(oldState.H), _blockSize, _blockSize, curDim, curDim-_blockSize);
00546           //
00547           // Get a view of the a block row of the Schur vectors.
00548           Teuchos::SerialDenseMatrix<int,ScalarType> subQ(Teuchos::View, *(oldState.Q), _blockSize, cur_nevBlocks, curDim-_blockSize);
00549           //
00550           // Get a view of the new B block of the updated Krylov-Schur factorization
00551           Teuchos::SerialDenseMatrix<int,ScalarType> newB(Teuchos::View, *newH,  _blockSize, cur_nevBlocks, cur_nevBlocks);
00552           //
00553           // Compute the new B block.
00554           blas.GEMM( Teuchos::NO_TRANS, Teuchos::NO_TRANS, _blockSize, cur_nevBlocks, _blockSize, one, 
00555                      oldB.values(), oldB.stride(), subQ.values(), subQ.stride(), zero, newB.values(), newB.stride() );
00556 
00557 
00558           //
00559           // Set the new state and initialize the solver.
00560           BlockKrylovSchurState<ScalarType,MV> newstate;
00561           if (_inSituRestart) {
00562             newstate.V = oldState.V;
00563           } else {
00564             newstate.V = workMV;
00565           }
00566           newstate.H = newH;
00567           newstate.curDim = cur_nevBlocks;
00568           bks_solver->initialize(newstate);
00569   
00570         } // end of restarting
00572         //
00573         // we returned from iterate(), but none of our status tests Passed.
00574         // something is wrong, and it is probably our fault.
00575         //
00577         else {
00578           TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::BlockKrylovSchurSolMgr::solve(): Invalid return from bks_solver::iterate().");
00579         }
00580       }
00581       catch (std::exception e) {
00582         printer->stream(Errors) << "Error! Caught exception in BlockKrylovSchur::iterate() at iteration " << bks_solver->getNumIters() << std::endl 
00583                                 << e.what() << std::endl;
00584         throw;
00585       }
00586     }
00587 
00588     //
00589     // free temporary space
00590     workMV = Teuchos::null;
00591   
00592     // Get the most current Ritz values before we return
00593     _ritzValues = bks_solver->getRitzValues();
00594     
00595     sol.numVecs = convtest->howMany();
00596     if (sol.numVecs > 0) {
00597       sol.index = bks_solver->getRitzIndex();
00598       sol.Evals = bks_solver->getRitzValues();
00599       // Check to see if conjugate pair is on the boundary.
00600       if (sol.index[sol.numVecs-1]==1) {
00601         sol.numVecs++;
00602         sol.Evals.resize(sol.numVecs);
00603         sol.index.resize(sol.numVecs);
00604         bks_solver->setNumRitzVectors(sol.numVecs);
00605       } else {
00606         sol.Evals.resize(sol.numVecs);
00607         sol.index.resize(sol.numVecs);
00608         bks_solver->setNumRitzVectors(sol.numVecs);
00609       }
00610       bks_solver->computeRitzVectors();
00611       sol.Evecs = MVT::CloneCopy( *(bks_solver->getRitzVectors()) );
00612       sol.Espace = sol.Evecs;
00613     } 
00614   }
00615 
00616   // print final summary
00617   bks_solver->currentStatus(printer->stream(FinalSummary));
00618 
00619   // print timing information
00620   Teuchos::TimeMonitor::summarize(printer->stream(TimingDetails));
00621 
00622   _problem->setSolution(sol);
00623   printer->stream(Debug) << "Returning " << sol.numVecs << " eigenpairs to eigenproblem." << std::endl;
00624 
00625   if (sol.numVecs < nev) {
00626     return Unconverged; // return from BlockKrylovSchurSolMgr::solve() 
00627   }
00628   return Converged; // return from BlockKrylovSchurSolMgr::solve() 
00629 }
00630 
00631 
00632 } // end Anasazi namespace
00633 
00634 #endif /* ANASAZI_BLOCK_KRYLOV_SCHUR_SOLMGR_HPP */

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