AnasaziBlockDavidson.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 
00033 #ifndef ANASAZI_BLOCK_DAVIDSON_HPP
00034 #define ANASAZI_BLOCK_DAVIDSON_HPP
00035 
00036 #include "AnasaziTypes.hpp"
00037 
00038 #include "AnasaziEigensolver.hpp"
00039 #include "AnasaziMultiVecTraits.hpp"
00040 #include "AnasaziOperatorTraits.hpp"
00041 #include "Teuchos_ScalarTraits.hpp"
00042 
00043 #include "AnasaziMatOrthoManager.hpp"
00044 #include "AnasaziModalSolverUtils.hpp"
00045 
00046 #include "Teuchos_LAPACK.hpp"
00047 #include "Teuchos_BLAS.hpp"
00048 #include "Teuchos_SerialDenseMatrix.hpp"
00049 #include "Teuchos_ParameterList.hpp"
00050 #include "Teuchos_TimeMonitor.hpp"
00051 
00062 namespace Anasazi {
00063 
00065 
00066 
00071   template <class ScalarType, class MV>
00072   struct BlockDavidsonState {
00077     int curDim;
00082     Teuchos::RefCountPtr<const MV> V;
00084     Teuchos::RefCountPtr<const MV> X; 
00086     Teuchos::RefCountPtr<const MV> KX; 
00088     Teuchos::RefCountPtr<const MV> MX;
00090     Teuchos::RefCountPtr<const MV> R;
00095     Teuchos::RefCountPtr<const MV> H;
00097     Teuchos::RefCountPtr<const std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> > T;
00103     Teuchos::RefCountPtr<const Teuchos::SerialDenseMatrix<int,ScalarType> > KK;
00104     BlockDavidsonState() : curDim(0), V(Teuchos::null),
00105                            X(Teuchos::null), KX(Teuchos::null), MX(Teuchos::null),
00106                            R(Teuchos::null), H(Teuchos::null),
00107                            T(Teuchos::null), KK(Teuchos::null) {}
00108   };
00109 
00111 
00113 
00114 
00127   class BlockDavidsonInitFailure : public AnasaziError {public:
00128     BlockDavidsonInitFailure(const std::string& what_arg) : AnasaziError(what_arg)
00129     {}};
00130 
00138   class BlockDavidsonOrthoFailure : public AnasaziError {public:
00139     BlockDavidsonOrthoFailure(const std::string& what_arg) : AnasaziError(what_arg)
00140     {}};
00141   
00143 
00144 
00145   template <class ScalarType, class MV, class OP>
00146   class BlockDavidson : public Eigensolver<ScalarType,MV,OP> { 
00147   public:
00149 
00150     
00158     BlockDavidson( const Teuchos::RefCountPtr<Eigenproblem<ScalarType,MV,OP> > &problem, 
00159                    const Teuchos::RefCountPtr<SortManager<ScalarType,MV,OP> > &sorter,
00160                    const Teuchos::RefCountPtr<OutputManager<ScalarType> > &printer,
00161                    const Teuchos::RefCountPtr<StatusTest<ScalarType,MV,OP> > &tester,
00162                    const Teuchos::RefCountPtr<MatOrthoManager<ScalarType,MV,OP> > &ortho,
00163                    Teuchos::ParameterList &params 
00164                  );
00165     
00167     virtual ~BlockDavidson() {};
00169 
00170 
00172 
00173 
00197     void iterate();
00198 
00220     void initialize(BlockDavidsonState<ScalarType,MV> state);
00221 
00225     void initialize();
00226 
00242     bool isInitialized() { return initialized_; }
00243 
00255     BlockDavidsonState<ScalarType,MV> getState() const {
00256       BlockDavidsonState<ScalarType,MV> state;
00257       state.curDim = curDim_;
00258       state.V = V_;
00259       state.X = X_;
00260       state.KX = KX_;
00261       if (hasM_) {
00262         state.MX = MX_;
00263       }
00264       else {
00265         state.MX = Teuchos::null;
00266       }
00267       state.R = R_;
00268       state.H = H_;
00269       state.KK = KK_;
00270       state.T = Teuchos::rcp(new std::vector<MagnitudeType>(theta_));
00271       return state;
00272     }
00273     
00275 
00276 
00278 
00279 
00281     int getNumIters() const { return(iter_); };
00282 
00284     void resetNumIters() { iter_=0; };
00285 
00293     Teuchos::RefCountPtr<const MV> getRitzVectors() {return X_;}
00294 
00300     std::vector<Value<ScalarType> > getRitzValues() { 
00301       std::vector<Value<ScalarType> > ret(curDim_);
00302       for (int i=0; i<curDim_; i++) {
00303         ret[i].realpart = theta_[i];
00304         ret[i].imagpart = ZERO;
00305       }
00306       return ret;
00307     }
00308 
00316     std::vector<int> getRitzIndex() {
00317       std::vector<int> ret(curDim_,0);
00318       return ret;
00319     }
00320 
00321 
00327     std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> getResNorms();
00328 
00329 
00335     std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> getRes2Norms();
00336 
00337 
00342     std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> getRitzRes2Norms() {
00343       std::vector<MagnitudeType> ret = ritz2norms_;
00344       ret.resize(curDim_);
00345       return ret;
00346     }
00347 
00348 
00354     int getCurSubspaceDim() const {
00355       if (!initialized_) return 0;
00356       return curDim_;
00357     }
00358 
00360     int getMaxSubspaceDim() const {return blockSize_*numBlocks_;}
00361 
00363 
00364 
00366 
00367 
00368 
00370     const Eigenproblem<ScalarType,MV,OP>& getProblem() const { return(*problem_); };
00371 
00381     void setBlockSize(int blockSize);
00382 
00384     int getBlockSize() const { return(blockSize_); }
00385 
00398     void setAuxVecs(const Teuchos::Array<Teuchos::RefCountPtr<const MV> > &auxvecs);
00399 
00401     Teuchos::Array<Teuchos::RefCountPtr<const MV> > getAuxVecs() const {return auxVecs_;}
00402 
00404 
00406 
00407 
00417     void setSize(int blockSize, int numBlocks);
00418 
00420 
00422 
00423 
00425     void currentStatus(ostream &os);
00426 
00428 
00429   private:
00430     //
00431     // Convenience typedefs
00432     //
00433     typedef MultiVecTraits<ScalarType,MV> MVT;
00434     typedef OperatorTraits<ScalarType,MV,OP> OPT;
00435     typedef Teuchos::ScalarTraits<ScalarType> SCT;
00436     typedef typename SCT::magnitudeType MagnitudeType;
00437     const MagnitudeType ONE;  
00438     const MagnitudeType ZERO; 
00439     const MagnitudeType NANVAL;
00440     //
00441     // Internal structs
00442     //
00443     struct CheckList {
00444       bool checkV;
00445       bool checkX, checkMX, checkKX;
00446       bool checkH, checkMH, checkKH;
00447       bool checkR, checkQ;
00448       bool checkKK;
00449       CheckList() : checkV(false),
00450                     checkX(false),checkMX(false),checkKX(false),
00451                     checkH(false),checkMH(false),checkKH(false),
00452                     checkR(false),checkQ(false),checkKK(false) {};
00453     };
00454     //
00455     // Internal methods
00456     //
00457     string accuracyCheck(const CheckList &chk, const string &where) const;
00458     //
00459     // Classes inputed through constructor that define the eigenproblem to be solved.
00460     //
00461     const Teuchos::RefCountPtr<Eigenproblem<ScalarType,MV,OP> >     problem_;
00462     const Teuchos::RefCountPtr<SortManager<ScalarType,MV,OP> >      sm_;
00463     const Teuchos::RefCountPtr<OutputManager<ScalarType> >          om_;
00464     const Teuchos::RefCountPtr<StatusTest<ScalarType,MV,OP> >       tester_;
00465     const Teuchos::RefCountPtr<MatOrthoManager<ScalarType,MV,OP> >  orthman_;
00466     //
00467     // Information obtained from the eigenproblem
00468     //
00469     Teuchos::RefCountPtr<OP> Op_;
00470     Teuchos::RefCountPtr<OP> MOp_;
00471     Teuchos::RefCountPtr<OP> Prec_;
00472     bool hasM_;
00473     //
00474     // Internal utilities class required by eigensolver.
00475     //
00476     ModalSolverUtils<ScalarType,MV,OP> MSUtils_;
00477     //
00478     // Internal timers
00479     //
00480     Teuchos::RefCountPtr<Teuchos::Time> timerOp_, timerMOp_, timerPrec_,
00481                                         timerSortEval_, timerDS_,
00482                                         timerLocal_, timerCompRes_, 
00483                                         timerOrtho_;
00484     //
00485     // Counters
00486     //
00487     int count_ApplyOp_, count_ApplyM_, count_ApplyPrec_;
00488 
00489     //
00490     // Algorithmic parameters.
00491     //
00492     // blockSize_ is the solver block size; it controls the number of eigenvectors that 
00493     // we compute, the number of residual vectors that we compute, and therefore the number
00494     // of vectors added to the basis on each iteration.
00495     int blockSize_;
00496     // numBlocks_ is the size of the allocated space for the Krylov basis, in blocks.
00497     int numBlocks_; 
00498     
00499     // 
00500     // Current solver state
00501     //
00502     // initialized_ specifies that the basis vectors have been initialized and the iterate() routine
00503     // is capable of running; _initialize is controlled  by the initialize() member method
00504     // For the implications of the state of initialized_, please see documentation for initialize()
00505     bool initialized_;
00506     //
00507     // curDim_ reflects how much of the current basis is valid 
00508     // NOTE: 0 <= curDim_ <= blockSize_*numBlocks_
00509     // this also tells us how many of the values in theta_ are valid Ritz values
00510     int curDim_;
00511     //
00512     // State Multivecs
00513     // H_,KH_,MH_ will not own any storage
00514     // H_ will occasionally point at the current block of vectors in the basis V_
00515     // MH_,KH_ will occasionally point at MX_,KX_ when they are used as temporary storage
00516     Teuchos::RefCountPtr<MV> X_, KX_, MX_, R_,
00517                              H_, KH_, MH_,
00518                              V_;
00519     //
00520     // Projected matrices
00521     //
00522     Teuchos::RefCountPtr<Teuchos::SerialDenseMatrix<int,ScalarType> > KK_;
00523     // 
00524     // auxiliary vectors
00525     Teuchos::Array<Teuchos::RefCountPtr<const MV> > auxVecs_;
00526     int numAuxVecs_;
00527     //
00528     // Number of iterations that have been performed.
00529     int iter_;
00530     // 
00531     // Current eigenvalues, residual norms
00532     std::vector<MagnitudeType> theta_, Rnorms_, R2norms_, ritz2norms_;
00533     // 
00534     // are the residual norms current with the residual?
00535     bool Rnorms_current_, R2norms_current_;
00536 
00537   };
00538 
00539 
00541   // Constructor
00542   template <class ScalarType, class MV, class OP>
00543   BlockDavidson<ScalarType,MV,OP>::BlockDavidson(
00544         const Teuchos::RefCountPtr<Eigenproblem<ScalarType,MV,OP> > &problem, 
00545         const Teuchos::RefCountPtr<SortManager<ScalarType,MV,OP> > &sorter,
00546         const Teuchos::RefCountPtr<OutputManager<ScalarType> > &printer,
00547         const Teuchos::RefCountPtr<StatusTest<ScalarType,MV,OP> > &tester,
00548         const Teuchos::RefCountPtr<MatOrthoManager<ScalarType,MV,OP> > &ortho,
00549         Teuchos::ParameterList &params
00550         ) :
00551     ONE(Teuchos::ScalarTraits<MagnitudeType>::one()),
00552     ZERO(Teuchos::ScalarTraits<MagnitudeType>::zero()),
00553     NANVAL(Teuchos::ScalarTraits<MagnitudeType>::nan()),
00554     // problem, tools
00555     problem_(problem), 
00556     sm_(sorter),
00557     om_(printer),
00558     tester_(tester),
00559     orthman_(ortho),
00560     MSUtils_(om_),
00561     // timers, counters
00562     timerOp_(Teuchos::TimeMonitor::getNewTimer("Operation Op*x")),
00563     timerMOp_(Teuchos::TimeMonitor::getNewTimer("Operation M*x")),
00564     timerPrec_(Teuchos::TimeMonitor::getNewTimer("Operation Prec*x")),
00565     timerSortEval_(Teuchos::TimeMonitor::getNewTimer("Sorting eigenvalues")),
00566     timerDS_(Teuchos::TimeMonitor::getNewTimer("Direct solve")),
00567     timerLocal_(Teuchos::TimeMonitor::getNewTimer("Local update")),
00568     timerCompRes_(Teuchos::TimeMonitor::getNewTimer("Computing residuals")),
00569     timerOrtho_(Teuchos::TimeMonitor::getNewTimer("Orthogonalization")),
00570     count_ApplyOp_(0),
00571     count_ApplyM_(0),
00572     count_ApplyPrec_(0),
00573     // internal data
00574     blockSize_(0),
00575     numBlocks_(0),
00576     initialized_(false),
00577     curDim_(0),
00578     auxVecs_( Teuchos::Array<Teuchos::RefCountPtr<const MV> >(0) ), 
00579     numAuxVecs_(0),
00580     iter_(0),
00581     Rnorms_current_(false),
00582     R2norms_current_(false)
00583   {     
00584     TEST_FOR_EXCEPTION(problem_ == Teuchos::null,std::invalid_argument,
00585                        "Anasazi::BlockDavidson::constructor: user passed null problem pointer.");
00586     TEST_FOR_EXCEPTION(sm_ == Teuchos::null,std::invalid_argument,
00587                        "Anasazi::BlockDavidson::constructor: user passed null sort manager pointer.");
00588     TEST_FOR_EXCEPTION(om_ == Teuchos::null,std::invalid_argument,
00589                        "Anasazi::BlockDavidson::constructor: user passed null output manager pointer.");
00590     TEST_FOR_EXCEPTION(tester_ == Teuchos::null,std::invalid_argument,
00591                        "Anasazi::BlockDavidson::constructor: user passed null status test pointer.");
00592     TEST_FOR_EXCEPTION(orthman_ == Teuchos::null,std::invalid_argument,
00593                        "Anasazi::BlockDavidson::constructor: user passed null orthogonalization manager pointer.");
00594     TEST_FOR_EXCEPTION(problem_->isProblemSet() == false, std::invalid_argument,
00595                        "Anasazi::BlockDavidson::constructor: problem is not set.");
00596     TEST_FOR_EXCEPTION(problem_->isHermitian() == false, std::invalid_argument,
00597                        "Anasazi::BlockDavidson::constructor: problem is not hermitian.");
00598 
00599     // get the problem operators
00600     Op_   = problem_->getOperator();
00601     TEST_FOR_EXCEPTION(Op_ == Teuchos::null, std::invalid_argument,
00602                        "Anasazi::BlockDavidson::constructor: problem provides no operator.");
00603     MOp_  = problem_->getM();
00604     Prec_ = problem_->getPrec();
00605     hasM_ = (MOp_ != Teuchos::null);
00606 
00607     // set the block size and allocate data
00608     int bs = params.get("Block Size", problem_->getNEV());
00609     int nb = params.get("Num Blocks", 2);
00610     setSize(bs,nb);
00611   }
00612 
00613 
00615   // Set the block size
00616   // This simply calls setSize(), modifying the block size while retaining the number of blocks.
00617   template <class ScalarType, class MV, class OP>
00618   void BlockDavidson<ScalarType,MV,OP>::setBlockSize (int blockSize) 
00619   {
00620     setSize(blockSize,numBlocks_);
00621   }
00622 
00623 
00625   // Set the block size and make necessary adjustments.
00626   template <class ScalarType, class MV, class OP>
00627   void BlockDavidson<ScalarType,MV,OP>::setSize (int blockSize, int numBlocks) 
00628   {
00629     // This routine only allocates space; it doesn't not perform any computation
00630     // any change in size will invalidate the state of the solver.
00631 
00632     TEST_FOR_EXCEPTION(blockSize < 1, std::invalid_argument, "Anasazi::BlockDavidson::setSize(): block size must be strictly positive.");
00633     TEST_FOR_EXCEPTION(numBlocks < 2, std::invalid_argument, "Anasazi::BlockDavidson::setSize(): num blocks must be greater than one.");
00634     if (blockSize == blockSize_ && numBlocks == numBlocks_) {
00635       // do nothing
00636       return;
00637     }
00638 
00639     blockSize_ = blockSize;
00640     numBlocks_ = numBlocks;
00641 
00642     Teuchos::RefCountPtr<const MV> tmp;
00643     // grab some Multivector to Clone
00644     // in practice, getInitVec() should always provide this, but it is possible to use a 
00645     // Eigenproblem with nothing in getInitVec() by manually initializing with initialize(); 
00646     // in case of that strange scenario, we will try to Clone from X_ first, then resort to getInitVec()
00647     if (X_ != Teuchos::null) { // this is equivalent to blockSize_ > 0
00648       tmp = X_;
00649     }
00650     else {
00651       tmp = problem_->getInitVec();
00652       TEST_FOR_EXCEPTION(tmp == Teuchos::null,std::invalid_argument,
00653                          "Anasazi::BlockDavidson::setSize(): Eigenproblem did not specify initial vectors to clone from");
00654     }
00655 
00656     TEST_FOR_EXCEPTION(numAuxVecs_+blockSize*numBlocks > MVT::GetVecLength(*tmp),std::invalid_argument,"Anasazi::BlockDavidson::setSize(): impossible subspace requirements.");
00657 
00658 
00660     // blockSize dependent
00661     //
00662     // grow/allocate vectors
00663     Rnorms_.resize(blockSize_,NANVAL);
00664     R2norms_.resize(blockSize_,NANVAL);
00665     //
00666     // clone multivectors off of tmp
00667     om_->print(Debug," >> Allocating X_\n");
00668     X_ = MVT::Clone(*tmp,blockSize_);
00669     om_->print(Debug," >> Allocating KX_\n");
00670     KX_ = MVT::Clone(*tmp,blockSize_);
00671     if (hasM_) {
00672       om_->print(Debug," >> Allocating MX_\n");
00673       MX_ = MVT::Clone(*tmp,blockSize_);
00674     }
00675     else {
00676       MX_ = X_;
00677     }
00678     om_->print(Debug," >> Allocating R_\n");
00679     R_ = MVT::Clone(*tmp,blockSize_);
00680 
00682     // blockSize*numBlocks dependent
00683     //
00684     int newsd = blockSize_*numBlocks_;
00685     theta_.resize(blockSize_*numBlocks_,NANVAL);
00686     ritz2norms_.resize(blockSize_*numBlocks_,NANVAL);
00687     om_->print(Debug," >> Allocating V_\n");
00688     V_ = MVT::Clone(*tmp,newsd);
00689     KK_ = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(newsd,newsd) );
00690 
00691     om_->print(Debug," >> done allocating.");
00692 
00693     initialized_ = false;
00694     curDim_ = 0;
00695   }
00696 
00697 
00699   // Set the auxiliary vectors
00700   template <class ScalarType, class MV, class OP>
00701   void BlockDavidson<ScalarType,MV,OP>::setAuxVecs(const Teuchos::Array<Teuchos::RefCountPtr<const MV> > &auxvecs) {
00702     typedef typename Teuchos::Array<Teuchos::RefCountPtr<const MV> >::iterator tarcpmv;
00703 
00704     // set new auxiliary vectors
00705     auxVecs_ = auxvecs;
00706     numAuxVecs_ = 0;
00707     for (tarcpmv i=auxVecs_.begin(); i != auxVecs_.end(); i++) {
00708       numAuxVecs_ += MVT::GetNumberVecs(**i);
00709     }
00710 
00711     // If the solver has been initialized, V is not necessarily orthogonal to new auxiliary vectors
00712     if (numAuxVecs_ > 0 && initialized_) {
00713       initialized_ = false;
00714     }
00715 
00716     if (om_->isVerbosity( Debug ) ) {
00717       CheckList chk;
00718       chk.checkQ = true;
00719       om_->print( Debug, accuracyCheck(chk, ": in setAuxVecs()") );
00720     }
00721   }
00722 
00723 
00725   /* Initialize the state of the solver
00726    * 
00727    * POST-CONDITIONS:
00728    *
00729    * V_ is orthonormal, orthogonal to auxVecs_, for first curDim_ vectors
00730    * theta_ contains Ritz w.r.t. V_(1:curDim_)
00731    * ritz2norms_ contains Ritz residuals w.r.t. V(1:curDim_)
00732    * X is Ritz vectors w.r.t. V_(1:curDim_)
00733    * KX = Op*X
00734    * MX = M*X if hasM_
00735    * R = KX - MX*diag(theta_)
00736    *
00737    */
00738   template <class ScalarType, class MV, class OP>
00739   void BlockDavidson<ScalarType,MV,OP>::initialize(BlockDavidsonState<ScalarType,MV> state)
00740   {
00741     // NOTE: memory has been allocated by setBlockSize(). Use setBlock below; do not Clone
00742 
00743     std::vector<int> bsind(blockSize_);
00744     for (int i=0; i<blockSize_; i++) bsind[i] = i;
00745 
00746     Teuchos::BLAS<int,ScalarType> blas;
00747 
00748     // in BlockDavidson, V is primary
00749     // the order of dependence follows like so.
00750     // --init->               V,KK
00751     //    --ritz analysis->   theta,X  
00752     //        --op apply->    KX,MX  
00753     //            --compute-> R
00754     // 
00755     // if the user specifies all data for a level, we will accept it.
00756     // otherwise, we will generate the whole level, and all subsequent levels.
00757     //
00758     // the data members are ordered based on dependence, and the levels are
00759     // partitioned according to the amount of work required to produce the
00760     // items in a level.
00761     //
00762     // inconsitent multivectors widths and lengths will not be tolerated, and
00763     // will be treated with exceptions.
00764 
00765     // set up V,KK: if the user doesn't specify these, ignore the rest
00766     if (state.V != Teuchos::null && state.KK != Teuchos::null) {
00767       TEST_FOR_EXCEPTION( MVT::GetVecLength(*state.V) != MVT::GetVecLength(*V_),
00768                           std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Vector length of V not correct." );
00769       TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*state.V) < blockSize_,
00770                           std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Specified V must have at least block size vectors.");
00771       TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*state.V) > blockSize_*numBlocks_,
00772                           std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Number of vectors in V must be less than getMaxSubspaceDim().");
00773 
00774       curDim_ = MVT::GetNumberVecs(*state.V);
00775       // pick an integral amount
00776       curDim_ = (int)(curDim_ / blockSize_)*blockSize_;
00777 
00778       TEST_FOR_EXCEPTION( curDim_ != MVT::GetNumberVecs(*state.V),
00779                           std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Number of vectors in V must be a multiple of getBlockSize().");
00780 
00781       // check size of KK
00782       TEST_FOR_EXCEPTION(state.KK->numRows() != curDim_ || state.KK->numCols() != curDim_, std::invalid_argument, 
00783                          "Anasazi::BlockDavidson::initialize(): Size of KK must be consistent with size of V.");
00784 
00785       std::vector<int> nevind(curDim_);
00786       for (int i=0; i<curDim_; i++) nevind[i] = i;
00787 
00788       // put data in V
00789       MVT::SetBlock(*state.V,nevind,*V_);
00790 
00791       // get local view of V: view of first curDim_ vectors
00792       // lclKV and lclMV will be temporarily allocated space for M*lclV and K*lclV
00793       Teuchos::RefCountPtr<MV> lclV, lclKV, lclMV;
00794       // generate lclV in case we need it below
00795       lclV = MVT::CloneView(*V_,nevind);
00796 
00797       // put data into KK_
00798       Teuchos::RefCountPtr<Teuchos::SerialDenseMatrix<int,ScalarType> > lclKK;
00799       lclKK = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(Teuchos::View,*KK_,curDim_,curDim_) );
00800       lclKK->assign(*state.KK);
00801       //
00802       // make lclKK hermitian in memory 
00803       for (int j=0; j<curDim_; j++) {
00804         for (int i=j+1; i<curDim_; i++) {
00805           (*lclKK)(i,j) = SCT::conjugate((*lclKK)(j,i));
00806         }
00807       }
00808 
00809       // X,theta require Ritz analisys; if we have to generate one of these, we might as well generate both
00810       if (state.X != Teuchos::null && state.T != Teuchos::null) {
00811         TEST_FOR_EXCEPTION(MVT::GetNumberVecs(*state.X) != blockSize_ || MVT::GetVecLength(*state.X) != MVT::GetVecLength(*X_),
00812                             std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Size of X must be consistent with block size and length of V.");
00813         TEST_FOR_EXCEPTION((signed int)(state.T->size()) != curDim_,
00814                             std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Size of T must be consistent with dimension of V.");
00815         MVT::SetBlock(*state.X,bsind,*X_);
00816         std::copy(state.T->begin(),state.T->end(),theta_.begin());
00817 
00818         // we don't have primitive ritz vector
00819         for (int i=0; i<curDim_; i++) ritz2norms_[i] = NANVAL;
00820       }
00821       else {
00822         // compute ritz vecs/vals
00823         Teuchos::SerialDenseMatrix<int,ScalarType> S(curDim_,curDim_);
00824         {
00825           Teuchos::TimeMonitor lcltimer( *timerDS_ );
00826           int rank = curDim_;
00827           MSUtils_.directSolver(curDim_, *lclKK, 0, &S, &theta_, &rank, 10);
00828           // we want all ritz values back
00829           TEST_FOR_EXCEPTION(rank != curDim_,BlockDavidsonInitFailure,
00830                              "Anasazi::BlockDavidson::initialize(): Not enough Ritz vectors to initialize algorithm.");
00831         }
00832         // sort ritz pairs
00833         {
00834           Teuchos::TimeMonitor lcltimer( *timerSortEval_ );
00835 
00836           std::vector<int> order(curDim_);
00837           //
00838           // sort the first curDim_ values in theta_
00839           sm_->sort( this, curDim_, theta_, &order );   // don't catch exception
00840           //
00841           // apply the same ordering to the primitive ritz vectors
00842           MSUtils_.permuteVectors(order,S);
00843         }
00844         // compute ritz residual norms
00845         {
00846           Teuchos::BLAS<int,ScalarType> blas;
00847           Teuchos::SerialDenseMatrix<int,ScalarType> R(curDim_,curDim_), T(curDim_,curDim_);
00848           // R = S*diag(theta) - KK*S
00849           for (int i=0; i<curDim_; i++) T(i,i) = theta_[i];
00850           int info = R.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,ONE,S,T,ZERO);
00851           TEST_FOR_EXCEPTION(info != 0, std::logic_error, "Anasazi::BlockDavidson::initialize(): Input error to SerialDenseMatrix::multiply.");
00852           info = R.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,-ONE,*lclKK,S,ONE);
00853           TEST_FOR_EXCEPTION(info != 0, std::logic_error, "Anasazi::BlockDavidson::initialize(): Input error to SerialDenseMatrix::multiply.");
00854           for (int i=0; i<curDim_; i++) {
00855             ritz2norms_[i] = blas.NRM2(curDim_,R[i],1);
00856           }
00857         }
00858 
00859         // compute eigenvectors
00860         Teuchos::SerialDenseMatrix<int,ScalarType> S1(Teuchos::View,S,curDim_,blockSize_);
00861         {
00862           Teuchos::TimeMonitor lcltimer( *timerLocal_ );
00863 
00864           // X <- lclV*S
00865           MVT::MvTimesMatAddMv( ONE, *lclV, S1, ZERO, *X_ );
00866         }
00867         // we generated theta,X so we don't want to use the user's KX,MX
00868         state.KX = Teuchos::null;
00869         state.MX = Teuchos::null;
00870       }
00871 
00872       // done with local pointers
00873       lclV = Teuchos::null;
00874       lclKK = Teuchos::null;
00875 
00876       // set up KX,MX
00877       if ( state.KX != Teuchos::null && (!hasM_ || state.MX != Teuchos::null) ) {
00878         TEST_FOR_EXCEPTION(MVT::GetNumberVecs(*state.KX) != blockSize_ || MVT::GetVecLength(*state.KX) != MVT::GetVecLength(*X_),
00879                             std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Size of KX must be consistent with block size and length of X.");
00880         if (hasM_) {
00881           TEST_FOR_EXCEPTION(MVT::GetNumberVecs(*state.MX) != blockSize_ || MVT::GetVecLength(*state.KX) != MVT::GetVecLength(*X_),
00882                               std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Size of MX must be consistent with block size and length of X.");
00883         }
00884         MVT::SetBlock(*state.KX,bsind,*KX_);
00885         if (hasM_) {
00886           MVT::SetBlock(*state.MX,bsind,*MX_);
00887         }
00888       }
00889       else {
00890         // generate KX,MX
00891         {
00892           Teuchos::TimeMonitor lcltimer( *timerOp_ );
00893           OPT::Apply(*Op_,*X_,*KX_);
00894           count_ApplyOp_ += blockSize_;
00895         }
00896         if (hasM_) {
00897           Teuchos::TimeMonitor lcltimer( *timerMOp_ );
00898           OPT::Apply(*MOp_,*X_,*MX_);
00899           count_ApplyM_ += blockSize_;
00900         }
00901         else {
00902           MX_ = X_;
00903         }
00904 
00905         // we generated KX,MX; we will generate R as well
00906         state.R = Teuchos::null;
00907       }
00908 
00909       // set up R
00910       if (state.R != Teuchos::null) {
00911         TEST_FOR_EXCEPTION(MVT::GetNumberVecs(*state.R) != blockSize_ || MVT::GetVecLength(*state.R) != MVT::GetVecLength(*X_),
00912                            std::invalid_argument, "Anasazi::BlockDavidson::initialize(): Size of R must be consistent with block size and length of X.");
00913         MVT::SetBlock(*state.R,bsind,*R_);
00914       }
00915       else {
00916         Teuchos::TimeMonitor lcltimer( *timerCompRes_ );
00917         
00918         // form R <- KX - MX*T
00919         MVT::MvAddMv(ZERO,*KX_,ONE,*KX_,*R_);
00920         Teuchos::SerialDenseMatrix<int,ScalarType> T(blockSize_,blockSize_);
00921         T.putScalar(ZERO);
00922         for (int i=0; i<blockSize_; i++) T(i,i) = theta_[i];
00923         MVT::MvTimesMatAddMv(-ONE,*MX_,T,ONE,*R_);
00924 
00925       }
00926 
00927       // R has been updated; mark the norms as out-of-date
00928       Rnorms_current_ = false;
00929       R2norms_current_ = false;
00930 
00931       // finally, we are initialized
00932       initialized_ = true;
00933 
00934       if (om_->isVerbosity( Debug ) ) {
00935         // Check almost everything here
00936         CheckList chk;
00937         chk.checkV = true;
00938         chk.checkX = true;
00939         chk.checkKX = true;
00940         chk.checkMX = true;
00941         chk.checkR = true;
00942         chk.checkQ = true;
00943         chk.checkKK = true;
00944         om_->print( Debug, accuracyCheck(chk, ": after initialize()") );
00945       }
00946 
00947       // Print information on current status
00948       if (om_->isVerbosity(Debug)) {
00949         currentStatus( om_->stream(Debug) );
00950       }
00951       else if (om_->isVerbosity(IterationDetails)) {
00952         currentStatus( om_->stream(IterationDetails) );
00953       }
00954     }
00955     else {
00956       // user did not specify a basis V
00957       // get vectors from problem or generate something, projectAndNormalize, call initialize() recursively
00958       Teuchos::RefCountPtr<const MV> ivec = problem_->getInitVec();
00959       TEST_FOR_EXCEPTION(ivec == Teuchos::null,std::invalid_argument,
00960                          "Anasazi::BlockDavdison::initialize(): Eigenproblem did not specify initial vectors to clone from.");
00961 
00962       int lclDim = MVT::GetNumberVecs(*ivec);
00963       // pick the largest multiple of blockSize_
00964       lclDim = (int)(lclDim / blockSize_)*blockSize_;
00965       bool userand = false;
00966       if (lclDim < blockSize_) {
00967         // we need at least blockSize_ vectors
00968         // use a random multivec: ignore everything from InitVec
00969         userand = true;
00970         lclDim = blockSize_;
00971       }
00972 
00973       // make an index
00974       std::vector<int> dimind(lclDim);
00975       for (int i=0; i<lclDim; i++) dimind[i] = i;
00976 
00977       // alloc newV, newKV, newMV
00978       Teuchos::RefCountPtr<MV> newMV, 
00979                                newKV = MVT::Clone(*ivec,lclDim),
00980                                newV  = MVT::Clone(*ivec,lclDim);
00981       if (userand) {
00982         MVT::MvRandom(*newV);
00983       }
00984       else {
00985         // assign ivec to first part of newV
00986         MVT::SetBlock(*ivec,dimind,*newV);
00987       }
00988 
00989       // compute newMV if hasM_
00990       if (hasM_) {
00991         newMV = MVT::Clone(*newV,lclDim);
00992         {
00993           Teuchos::TimeMonitor lcltimer( *timerMOp_ );
00994           OPT::Apply(*MOp_,*newV,*newMV);
00995           count_ApplyM_ += lclDim;
00996         }
00997       }
00998       else {
00999         newMV = Teuchos::null;
01000       }
01001 
01002       // remove auxVecs from newV and normalize newV
01003       if (auxVecs_.size() > 0) {
01004         Teuchos::TimeMonitor lcltimer( *timerOrtho_ );
01005 
01006         Teuchos::Array<Teuchos::RefCountPtr<Teuchos::SerialDenseMatrix<int,ScalarType> > > dummy;
01007         int rank = orthman_->projectAndNormalize(*newV,newMV,dummy,Teuchos::null,auxVecs_);
01008         TEST_FOR_EXCEPTION(rank != lclDim,BlockDavidsonInitFailure,
01009                            "Anasazi::BlockDavidson::initialize(): Couldn't generate initial basis of full rank.");
01010       }
01011       else {
01012         Teuchos::TimeMonitor lcltimer( *timerOrtho_ );
01013 
01014         int rank = orthman_->normalize(*newV,newMV,Teuchos::null);
01015         TEST_FOR_EXCEPTION(rank != lclDim,BlockDavidsonInitFailure,
01016                            "Anasazi::BlockDavidson::initialize(): Couldn't generate initial basis of full rank.");
01017       }
01018 
01019       // compute newKV
01020       {
01021         Teuchos::TimeMonitor lcltimer( *timerOp_ );
01022         OPT::Apply(*Op_,*newV,*newKV);
01023         count_ApplyOp_ += lclDim;
01024       }
01025 
01026       // generate KK
01027       Teuchos::RefCountPtr< Teuchos::SerialDenseMatrix<int,ScalarType> > KK;
01028       KK = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(lclDim,lclDim) );
01029       MVT::MvTransMv(ONE,*newV,*newKV,*KK);
01030 
01031       // clear newKV,newMV
01032       newKV = newMV = Teuchos::null;
01033 
01034       // call myself recursively
01035       BlockDavidsonState<ScalarType,MV> newstate;
01036       newstate.V = newV;
01037       newstate.KK = KK;
01038       initialize(newstate);
01039     }
01040   }
01041 
01042 
01044   // initialize the solver with default state
01045   template <class ScalarType, class MV, class OP>
01046   void BlockDavidson<ScalarType,MV,OP>::initialize()
01047   {
01048     BlockDavidsonState<ScalarType,MV> empty;
01049     initialize(empty);
01050   }
01051 
01052 
01054   // Perform BlockDavidson iterations until the StatusTest tells us to stop.
01055   template <class ScalarType, class MV, class OP>
01056   void BlockDavidson<ScalarType,MV,OP>::iterate ()
01057   {
01058     //
01059     // Initialize solver state
01060     if (initialized_ == false) {
01061       initialize();
01062     }
01063 
01064     // as a data member, this would be redundant and require synchronization with
01065     // blockSize_ and numBlocks_; we'll use a constant here.
01066     const int searchDim = blockSize_*numBlocks_;
01067 
01068     Teuchos::BLAS<int,ScalarType> blas;
01069 
01070     //
01071     // The projected matrices are part of the state, but the eigenvectors are defined locally.
01072     //    S = Local eigenvectors         (size: searchDim * searchDim
01073     Teuchos::SerialDenseMatrix<int,ScalarType> S( searchDim, searchDim );
01074 
01075 
01077     // iterate until the status test tells us to stop.
01078     // also break if our basis is full
01079     while (tester_->checkStatus(this) != Passed && curDim_ < searchDim) {
01080 
01081       // Print information on current iteration
01082       if (om_->isVerbosity(Debug)) {
01083         currentStatus( om_->stream(Debug) );
01084       }
01085       else if (om_->isVerbosity(IterationDetails)) {
01086         currentStatus( om_->stream(IterationDetails) );
01087       }
01088 
01089       iter_++;
01090 
01091       // get the current part of the basis
01092       std::vector<int> curind(blockSize_);
01093       for (int i=0; i<blockSize_; i++) curind[i] = curDim_ + i;
01094       H_ = MVT::CloneView(*V_,curind);
01095       
01096       // Apply the preconditioner on the residuals: H <- Prec*R
01097       // H = Prec*R
01098       if (Prec_ != Teuchos::null) {
01099         Teuchos::TimeMonitor lcltimer( *timerPrec_ );
01100         OPT::Apply( *Prec_, *R_, *H_ );   // don't catch the exception
01101         count_ApplyPrec_ += blockSize_;
01102       }
01103       else {
01104         std::vector<int> bsind(blockSize_);
01105         for (int i=0; i<blockSize_; i++) { bsind[i] = i; }
01106         MVT::SetBlock(*R_,bsind,*H_);
01107       }
01108 
01109       // Apply the mass matrix on H
01110       if (hasM_) {
01111         // use memory at MX_ for temporary storage
01112         MH_ = MX_;
01113         Teuchos::TimeMonitor lcltimer( *timerMOp_ );
01114         OPT::Apply( *MOp_, *H_, *MH_);    // don't catch the exception
01115         count_ApplyM_ += blockSize_;
01116       }
01117       else  {
01118         MH_ = H_;
01119       }
01120 
01121       // Get a view of the previous vectors
01122       // this is used for orthogonalization and for computing V^H K H
01123       std::vector<int> prevind(curDim_);
01124       for (int i=0; i<curDim_; i++) prevind[i] = i;
01125       Teuchos::RefCountPtr<MV> Vprev = MVT::CloneView(*V_,prevind);
01126 
01127       // Orthogonalize H against the previous vectors and the auxiliary vectors, and normalize
01128       {
01129         Teuchos::TimeMonitor lcltimer( *timerOrtho_ );
01130 
01131         Teuchos::Array<Teuchos::RefCountPtr<const MV> > against = auxVecs_;
01132         against.push_back(Vprev);
01133         int rank = orthman_->projectAndNormalize(*H_,MH_,
01134                                             Teuchos::tuple<Teuchos::RefCountPtr<Teuchos::SerialDenseMatrix<int,ScalarType> > >(Teuchos::null),
01135                                             Teuchos::null,against);
01136         TEST_FOR_EXCEPTION(rank != blockSize_,BlockDavidsonOrthoFailure,
01137                            "Anasazi::BlockDavidson::iterate(): unable to compute full basis for H.");
01138       }
01139 
01140       // Apply the stiffness matrix to H
01141       {
01142         // use memory at KX_ for temporary storage
01143         KH_ = KX_;
01144         Teuchos::TimeMonitor lcltimer( *timerOp_ );
01145         OPT::Apply( *Op_, *H_, *KH_);    // don't catch the exception
01146         count_ApplyOp_ += blockSize_;
01147       }
01148 
01149       if (om_->isVerbosity( Debug ) ) {
01150         CheckList chk;
01151         chk.checkH = true;
01152         chk.checkMH = true;
01153         chk.checkKH = true;
01154         om_->print( Debug, accuracyCheck(chk, ": after ortho H") );
01155       }
01156       else if (om_->isVerbosity( OrthoDetails ) ) {
01157         CheckList chk;
01158         chk.checkH = true;
01159         chk.checkMH = true;
01160         chk.checkKH = true;
01161         om_->print( OrthoDetails, accuracyCheck(chk,": after ortho H") );
01162       }
01163 
01164       // compute next part of the projected matrices
01165       // this this in two parts
01166       Teuchos::RefCountPtr<Teuchos::SerialDenseMatrix<int,ScalarType> > nextKK;
01167       // Vprev*K*H
01168       nextKK = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(Teuchos::View,*KK_,curDim_,blockSize_,0,curDim_) );
01169       MVT::MvTransMv(ONE,*Vprev,*KH_,*nextKK);
01170       // H*K*H
01171       nextKK = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(Teuchos::View,*KK_,blockSize_,blockSize_,curDim_,curDim_) );
01172       MVT::MvTransMv(ONE,*H_,*KH_,*nextKK);
01173       // 
01174       // make sure that KK_ is hermitian in memory
01175       nextKK = Teuchos::null;
01176       for (int i=curDim_; i<curDim_+blockSize_; i++) {
01177         for (int j=0; j<i; j++) {
01178           (*KK_)(i,j) = SCT::conjugate((*KK_)(j,i));
01179         }
01180       }
01181 
01182       // V has been extended, and KK has been extended. Update basis dim and release all pointers.
01183       curDim_ += blockSize_;
01184       H_ = KH_ = MH_ = Teuchos::null;
01185       Vprev = Teuchos::null;
01186 
01187       if (om_->isVerbosity( Debug ) ) {
01188         CheckList chk;
01189         chk.checkKK = true;
01190         om_->print( Debug, accuracyCheck(chk, ": after expanding KK") );
01191       }
01192 
01193       // Get pointer to complete basis
01194       curind.resize(curDim_);
01195       for (int i=0; i<curDim_; i++) curind[i] = i;
01196       Teuchos::RefCountPtr<const MV> curV = MVT::CloneView(*V_,curind);
01197 
01198       // Perform spectral decomposition
01199       {
01200         Teuchos::TimeMonitor lcltimer(*timerDS_);
01201         int nevlocal = curDim_;
01202         int info = MSUtils_.directSolver(curDim_,*KK_,0,&S,&theta_,&nevlocal,10);
01203         TEST_FOR_EXCEPTION(info != 0,std::logic_error,"Anasazi::BlockDavidson::iterate(): direct solve returned error code.");
01204         // we did not ask directSolver to perform deflation, so nevLocal better be curDim_
01205         TEST_FOR_EXCEPTION(nevlocal != curDim_,std::logic_error,"Anasazi::BlockDavidson::iterate(): direct solve did not compute all eigenvectors."); // this should never happen
01206       }
01207 
01208       // Sort ritz pairs
01209       { 
01210         Teuchos::TimeMonitor lcltimer( *timerSortEval_ );
01211 
01212         std::vector<int> order(curDim_);
01213         // 
01214         // sort the first curDim_ values in theta_
01215         sm_->sort( this, curDim_, theta_, &order );   // don't catch exception
01216         //
01217         // apply the same ordering to the primitive ritz vectors
01218         Teuchos::SerialDenseMatrix<int,ScalarType> curS(Teuchos::View,S,curDim_,curDim_);
01219         MSUtils_.permuteVectors(order,curS);
01220       }
01221 
01222       // compute ritz residual norms
01223       {
01224         Teuchos::BLAS<int,ScalarType> blas;
01225         Teuchos::SerialDenseMatrix<int,ScalarType> R(curDim_,curDim_), T(curDim_,curDim_);
01226         Teuchos::SerialDenseMatrix<int,ScalarType> curKK(Teuchos::View,*KK_,curDim_,curDim_),
01227                                                     curS(Teuchos::View,S,curDim_,curDim_);
01228         // R = S*diag(theta) - KK*S
01229         for (int i=0; i<curDim_; i++) T(i,i) = theta_[i];
01230         int info = R.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,ONE,curS,T,ZERO);
01231         TEST_FOR_EXCEPTION(info != 0, std::logic_error, "Anasazi::BlockDavidson::iterate(): Input error to SerialDenseMatrix::multiply.");
01232         info = R.multiply(Teuchos::NO_TRANS,Teuchos::NO_TRANS,-ONE,curKK,curS,ONE);
01233         TEST_FOR_EXCEPTION(info != 0, std::logic_error, "Anasazi::BlockDavidson::iterate(): Input error to SerialDenseMatrix::multiply.");
01234         for (int i=0; i<curDim_; i++) {
01235           ritz2norms_[i] = blas.NRM2(curDim_,R[i],1);
01236         }
01237       }
01238 
01239       // Create a view matrix of the first blockSize_ vectors
01240       Teuchos::SerialDenseMatrix<int,ScalarType> S1( Teuchos::View, S, curDim_, blockSize_ );
01241 
01242       // Compute the new Ritz vectors
01243       {
01244         Teuchos::TimeMonitor lcltimer( *timerLocal_ );
01245         MVT::MvTimesMatAddMv(ONE,*curV,S1,ZERO,*X_);
01246       }
01247 
01248       // Apply the stiffness matrix for the Ritz vectors
01249       {
01250         Teuchos::TimeMonitor lcltimer( *timerOp_ );
01251         OPT::Apply( *Op_, *X_, *KX_);    // don't catch the exception
01252         count_ApplyOp_ += blockSize_;
01253       }
01254       // Apply the mass matrix for the Ritz vectors
01255       if (hasM_) {
01256         Teuchos::TimeMonitor lcltimer( *timerMOp_ );
01257         OPT::Apply(*MOp_,*X_,*MX_);
01258         count_ApplyM_ += blockSize_;
01259       }
01260       else {
01261         MX_ = X_;
01262       }
01263 
01264       // Compute the residual
01265       // R = KX - MX*diag(theta)
01266       {
01267         Teuchos::TimeMonitor lcltimer( *timerCompRes_ );
01268         
01269         MVT::MvAddMv( ONE, *KX_, ZERO, *KX_, *R_ );
01270         Teuchos::SerialDenseMatrix<int,ScalarType> T( blockSize_, blockSize_ );
01271         for (int i = 0; i < blockSize_; i++) {
01272           T(i,i) = theta_[i];
01273         }
01274         MVT::MvTimesMatAddMv( -ONE, *MX_, T, ONE, *R_ );
01275       }
01276 
01277       // R has been updated; mark the norms as out-of-date
01278       Rnorms_current_ = false;
01279       R2norms_current_ = false;
01280 
01281 
01282       // When required, monitor some orthogonalities
01283       if (om_->isVerbosity( Debug ) ) {
01284         // Check almost everything here
01285         CheckList chk;
01286         chk.checkV = true;
01287         chk.checkX = true;
01288         chk.checkKX = true;
01289         chk.checkMX = true;
01290         chk.checkR = true;
01291         om_->print( Debug, accuracyCheck(chk, ": after local update") );
01292       }
01293       else if (om_->isVerbosity( OrthoDetails )) {
01294         CheckList chk;
01295         chk.checkX = true;
01296         chk.checkKX = true;
01297         chk.checkMX = true;
01298         chk.checkR = true;
01299         om_->print( OrthoDetails, accuracyCheck(chk, ": after local update") );
01300       }
01301     } // end while (statusTest == false)
01302 
01303   } // end of iterate()
01304 
01305 
01306 
01308   // compute/return residual M-norms
01309   template <class ScalarType, class MV, class OP>
01310   std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> 
01311   BlockDavidson<ScalarType,MV,OP>::getResNorms() {
01312     if (Rnorms_current_ == false) {
01313       // Update the residual norms
01314       orthman_->norm(*R_,&Rnorms_);
01315       Rnorms_current_ = true;
01316     }
01317     return Rnorms_;
01318   }
01319 
01320   
01322   // compute/return residual 2-norms
01323   template <class ScalarType, class MV, class OP>
01324   std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> 
01325   BlockDavidson<ScalarType,MV,OP>::getRes2Norms() {
01326     if (R2norms_current_ == false) {
01327       // Update the residual 2-norms 
01328       MVT::MvNorm(*R_,&R2norms_);
01329       R2norms_current_ = true;
01330     }
01331     return R2norms_;
01332   }
01333 
01334 
01336   // Check accuracy, orthogonality, and other debugging stuff
01337   // 
01338   // bools specify which tests we want to run (instead of running more than we actually care about)
01339   //
01340   // we don't bother checking the following because they are computed explicitly:
01341   //    H == Prec*R
01342   //   KH == K*H
01343   //
01344   // 
01345   // checkV : V orthonormal
01346   //          orthogonal to auxvecs
01347   // checkX : X orthonormal
01348   //          orthogonal to auxvecs
01349   // checkMX: check MX == M*X
01350   // checkKX: check KX == K*X
01351   // checkH : H orthonormal 
01352   //          orthogonal to V and H and auxvecs
01353   // checkMH: check MH == M*H
01354   // checkR : check R orthogonal to X
01355   // checkQ : check that auxiliary vectors are actually orthonormal
01356   // checkKK: check that KK is symmetric in memory 
01357   //
01358   // TODO: 
01359   //  add checkTheta 
01360   //
01361   template <class ScalarType, class MV, class OP>
01362   std::string BlockDavidson<ScalarType,MV,OP>::accuracyCheck( const CheckList &chk, const string &where ) const 
01363   {
01364     stringstream os;
01365     os.precision(2);
01366     os.setf(ios::scientific, ios::floatfield);
01367     MagnitudeType tmp;
01368 
01369     os << " Debugging checks: iteration " << iter_ << where << endl;
01370 
01371     // V and friends
01372     std::vector<int> lclind(curDim_);
01373     for (int i=0; i<curDim_; i++) lclind[i] = i;
01374     Teuchos::RefCountPtr<MV> lclV,lclKV;
01375     if (initialized_) {
01376       lclV = MVT::CloneView(*V_,lclind);
01377     }
01378     if (chk.checkV && initialized_) {
01379       tmp = orthman_->orthonormError(*lclV);
01380       os << " >> Error in V^H M V == I  : " << tmp << endl;
01381       for (unsigned int i=0; i<auxVecs_.size(); i++) {
01382         tmp = orthman_->orthogError(*lclV,*auxVecs_[i]);
01383         os << " >> Error in V^H M Q[" << i << "] == 0 : " << tmp << endl;
01384       }
01385       Teuchos::SerialDenseMatrix<int,ScalarType> curKK(curDim_,curDim_);
01386       Teuchos::RefCountPtr<MV> lclKV = MVT::Clone(*V_,curDim_);
01387       OPT::Apply(*Op_,*lclV,*lclKV);
01388       MVT::MvTransMv(ONE,*lclV,*lclKV,curKK);
01389       Teuchos::SerialDenseMatrix<int,ScalarType> subKK(Teuchos::View,*KK_,curDim_,curDim_);
01390       curKK -= subKK;
01391       // dup the lower tri part
01392       for (int j=0; j<curDim_; j++) {
01393         for (int i=j+1; i<curDim_; i++) {
01394           curKK(i,j) = curKK(j,i);
01395         }
01396       }
01397       os << " >> Error in V^H K V == KK : " << curKK.normFrobenius() << endl;
01398     }
01399 
01400     // X and friends
01401     if (chk.checkX && initialized_) {
01402       tmp = orthman_->orthonormError(*X_);
01403       os << " >> Error in X^H M X == I  : " << tmp << endl;
01404       for (unsigned int i=0; i<auxVecs_.size(); i++) {
01405         tmp = orthman_->orthogError(*X_,*auxVecs_[i]);
01406         os << " >> Error in X^H M Q[" << i << "] == 0 : " << tmp << endl;
01407       }
01408     }
01409     if (chk.checkMX && hasM_ && initialized_) {
01410       tmp = MSUtils_.errorEquality(X_.get(), MX_.get(), MOp_.get());
01411       os << " >> Error in MX == M*X     : " << tmp << endl;
01412     }
01413     if (chk.checkKX && initialized_) {
01414       tmp = MSUtils_.errorEquality(X_.get(), KX_.get(), Op_.get());
01415       os << " >> Error in KX == K*X     : " << tmp << endl;
01416     }
01417 
01418     // H and friends
01419     if (chk.checkH && initialized_) {
01420       tmp = orthman_->orthonormError(*H_);
01421       os << " >> Error in H^H M H == I  : " << tmp << endl;
01422       tmp = orthman_->orthogError(*H_,*lclV);
01423       os << " >> Error in H^H M V == 0  : " << tmp << endl;
01424       tmp = orthman_->orthogError(*H_,*X_);
01425       os << " >> Error in H^H M X == 0  : " << tmp << endl;
01426       for (unsigned int i=0; i<auxVecs_.size(); i++) {
01427         tmp = orthman_->orthogError(*H_,*auxVecs_[i]);
01428         os << " >> Error in H^H M Q[" << i << "] == 0 : " << tmp << endl;
01429       }
01430     }
01431     if (chk.checkKH && initialized_) {
01432       tmp = MSUtils_.errorEquality(H_.get(), KH_.get(), Op_.get());
01433       os << " >> Error in KH == K*H     : " << tmp << endl;
01434     }
01435     if (chk.checkMH && hasM_ && initialized_) {
01436       tmp = MSUtils_.errorEquality(H_.get(), MH_.get(), MOp_.get());
01437       os << " >> Error in MH == M*H     : " << tmp << endl;
01438     }
01439 
01440     // R: this is not M-orthogonality, but standard euclidean orthogonality
01441     if (chk.checkR && initialized_) {
01442       Teuchos::SerialDenseMatrix<int,ScalarType> xTx(blockSize_,blockSize_);
01443       MVT::MvTransMv(ONE,*X_,*R_,xTx);
01444       tmp = xTx.normFrobenius();
01445       os << " >> Error in X^H R == 0    : " << tmp << endl;
01446     }
01447 
01448     // KK
01449     if (chk.checkKK && initialized_) {
01450       Teuchos::SerialDenseMatrix<int,ScalarType> tmp(curDim_,curDim_), lclKK(Teuchos::View,*KK_,curDim_,curDim_);
01451       for (int j=0; j<curDim_; j++) {
01452         for (int i=0; i<curDim_; i++) {
01453           tmp(i,j) = lclKK(i,j) - SCT::conjugate(lclKK(j,i));
01454         }
01455       }
01456       os << " >> Error in KK - KK^H == 0 : " << tmp.normFrobenius() << endl;
01457     }
01458 
01459     // Q
01460     if (chk.checkQ) {
01461       for (unsigned int i=0; i<auxVecs_.size(); i++) {
01462         tmp = orthman_->orthonormError(*auxVecs_[i]);
01463         os << " >> Error in Q[" << i << "]^H M Q[" << i << "] == I : " << tmp << endl;
01464         for (unsigned int j=i+1; j<auxVecs_.size(); j++) {
01465           tmp = orthman_->orthogError(*auxVecs_[i],*auxVecs_[j]);
01466           os << " >> Error in Q[" << i << "]^H M Q[" << j << "] == 0 : " << tmp << endl;
01467         }
01468       }
01469     }
01470 
01471     os << endl;
01472 
01473     return os.str();
01474   }
01475 
01476 
01478   // Print the current status of the solver
01479   template <class ScalarType, class MV, class OP>
01480   void 
01481   BlockDavidson<ScalarType,MV,OP>::currentStatus(ostream &os) 
01482   {
01483     os.setf(ios::scientific, ios::floatfield);
01484     os.precision(6);
01485     os <<endl;
01486     os <<"================================================================================" << endl;
01487     os << endl;
01488     os <<"                          BlockDavidson Solver Status" << endl;
01489     os << endl;
01490     os <<"The solver is "<<(initialized_ ? "initialized." : "not initialized.") << endl;
01491     os <<"The number of iterations performed is " <<iter_<<endl;
01492     os <<"The block size is         " << blockSize_<<endl;
01493     os <<"The number of blocks is   " << numBlocks_<<endl;
01494     os <<"The current basis size is " << curDim_<<endl;
01495     os <<"The number of auxiliary vectors is    " << numAuxVecs_ << endl;
01496     os <<"The number of operations Op*x   is "<<count_ApplyOp_<<endl;
01497     os <<"The number of operations M*x    is "<<count_ApplyM_<<endl;
01498     os <<"The number of operations Prec*x is "<<count_ApplyPrec_<<endl;
01499 
01500     os.setf(ios_base::right, ios_base::adjustfield);
01501 
01502     if (initialized_) {
01503       os << endl;
01504       os <<"CURRENT EIGENVALUE ESTIMATES             "<<endl;
01505       os << std::setw(20) << "Eigenvalue" 
01506          << std::setw(20) << "Residual(M)"
01507          << std::setw(20) << "Residual(2)"
01508          << endl;
01509       os <<"--------------------------------------------------------------------------------"<<endl;
01510       for (int i=0; i<blockSize_; i++) {
01511         os << std::setw(20) << theta_[i];
01512         if (Rnorms_current_) os << std::setw(20) << Rnorms_[i];
01513         else os << std::setw(20) << "not current";
01514         if (R2norms_current_) os << std::setw(20) << R2norms_[i];
01515         else os << std::setw(20) << "not current";
01516         os << endl;
01517       }
01518     }
01519     os <<"================================================================================" << endl;
01520     os << endl;
01521   }
01522   
01523 } // End of namespace Anasazi
01524 
01525 #endif
01526 
01527 // End of file AnasaziBlockDavidson.hpp

Generated on Thu Sep 18 12:31:34 2008 for Anasazi by doxygen 1.3.9.1