Belos Package Browser (Single Doxygen Collection) Development
BelosBlockCGIter.hpp
Go to the documentation of this file.
00001 //@HEADER
00002 // ************************************************************************
00003 //
00004 //                 Belos: Block Linear Solvers Package
00005 //                  Copyright 2004 Sandia Corporation
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ************************************************************************
00040 //@HEADER
00041 
00042 #ifndef BELOS_BLOCK_CG_ITER_HPP
00043 #define BELOS_BLOCK_CG_ITER_HPP
00044 
00049 #include "BelosConfigDefs.hpp"
00050 #include "BelosTypes.hpp"
00051 #include "BelosCGIteration.hpp"
00052 
00053 #include "BelosLinearProblem.hpp"
00054 #include "BelosMatOrthoManager.hpp"
00055 #include "BelosOutputManager.hpp"
00056 #include "BelosStatusTest.hpp"
00057 #include "BelosOperatorTraits.hpp"
00058 #include "BelosMultiVecTraits.hpp"
00059 
00060 #include "Teuchos_BLAS.hpp"
00061 #include "Teuchos_LAPACK.hpp"
00062 #include "Teuchos_SerialDenseMatrix.hpp"
00063 #include "Teuchos_SerialDenseVector.hpp"
00064 #include "Teuchos_ScalarTraits.hpp"
00065 #include "Teuchos_ParameterList.hpp"
00066 #include "Teuchos_TimeMonitor.hpp"
00067 
00078 namespace Belos {
00079   
00080 template<class ScalarType, class MV, class OP>
00081 class BlockCGIter : virtual public CGIteration<ScalarType,MV,OP> {
00082 
00083   public:
00084     
00085   //
00086   // Convenience typedefs
00087   //
00088   typedef MultiVecTraits<ScalarType,MV> MVT;
00089   typedef OperatorTraits<ScalarType,MV,OP> OPT;
00090   typedef Teuchos::ScalarTraits<ScalarType> SCT;
00091   typedef typename SCT::magnitudeType MagnitudeType;
00092 
00094 
00095 
00101   BlockCGIter( const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > &problem, 
00102          const Teuchos::RCP<OutputManager<ScalarType> > &printer,
00103          const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > &tester,
00104          const Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP> > &ortho,
00105          Teuchos::ParameterList &params );
00106 
00108   virtual ~BlockCGIter() {};
00110 
00111 
00113 
00114   
00127   void iterate();
00128 
00143   void initializeCG(CGIterationState<ScalarType,MV> newstate);
00144 
00148   void initialize()
00149   {
00150     CGIterationState<ScalarType,MV> empty;
00151     initializeCG(empty);
00152   }
00153   
00160   CGIterationState<ScalarType,MV> getState() const {
00161     CGIterationState<ScalarType,MV> state;
00162     state.R = R_;
00163     state.P = P_;
00164     state.AP = AP_;
00165     state.Z = Z_;
00166     return state;
00167   }
00168 
00170 
00171   
00173 
00174 
00176   int getNumIters() const { return iter_; }
00177   
00179   void resetNumIters( int iter=0 ) { iter_ = iter; }
00180 
00183   Teuchos::RCP<const MV> getNativeResiduals( std::vector<MagnitudeType> *norms ) const { return R_; }
00184 
00186 
00188   Teuchos::RCP<MV> getCurrentUpdate() const { return Teuchos::null; }
00189 
00191   
00193 
00194 
00196   const LinearProblem<ScalarType,MV,OP>& getProblem() const { return *lp_; }
00197 
00199   int getBlockSize() const { return blockSize_; }
00200 
00202   void setBlockSize(int blockSize);
00203 
00205   bool isInitialized() { return initialized_; }
00206 
00208 
00209   private:
00210 
00211   //
00212   // Internal methods
00213   //
00215   void setStateSize();
00216   
00217   //
00218   // Classes inputed through constructor that define the linear problem to be solved.
00219   //
00220   const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> >    lp_;
00221   const Teuchos::RCP<OutputManager<ScalarType> >          om_;
00222   const Teuchos::RCP<StatusTest<ScalarType,MV,OP> >       stest_;
00223   const Teuchos::RCP<OrthoManager<ScalarType,MV> >        ortho_;
00224 
00225   //
00226   // Algorithmic parameters
00227   //
00228   // blockSize_ is the solver block size.
00229   int blockSize_;
00230 
00231   //  
00232   // Current solver state
00233   //
00234   // initialized_ specifies that the basis vectors have been initialized and the iterate() routine
00235   // is capable of running; _initialize is controlled  by the initialize() member method
00236   // For the implications of the state of initialized_, please see documentation for initialize()
00237   bool initialized_;
00238 
00239   // stateStorageInitialized_ specified that the state storage has be initialized.
00240   // This initialization may be postponed if the linear problem was generated without 
00241   // the right-hand side or solution vectors.
00242   bool stateStorageInitialized_;
00243 
00244   // Current subspace dimension, and number of iterations performed.
00245   int iter_;
00246   
00247   // 
00248   // State Storage
00249   // 
00250   // Residual
00251   Teuchos::RCP<MV> R_;
00252   //
00253   // Preconditioned residual
00254   Teuchos::RCP<MV> Z_;
00255   //
00256   // Direction std::vector
00257   Teuchos::RCP<MV> P_;
00258   //
00259   // Operator applied to direction std::vector
00260   Teuchos::RCP<MV> AP_;
00261 
00262 };
00263 
00265   // Constructor.
00266   template<class ScalarType, class MV, class OP>
00267   BlockCGIter<ScalarType,MV,OP>::BlockCGIter(const Teuchos::RCP<LinearProblem<ScalarType,MV,OP> > &problem, 
00268                const Teuchos::RCP<OutputManager<ScalarType> > &printer,
00269                const Teuchos::RCP<StatusTest<ScalarType,MV,OP> > &tester,
00270                const Teuchos::RCP<MatOrthoManager<ScalarType,MV,OP> > &ortho,
00271                Teuchos::ParameterList &params ):
00272     lp_(problem),
00273     om_(printer),
00274     stest_(tester),
00275     ortho_(ortho),
00276     blockSize_(0),
00277     initialized_(false),
00278     stateStorageInitialized_(false),
00279     iter_(0)
00280   {
00281     // Set the block size and allocate data
00282     int bs = params.get("Block Size", 1);
00283     setBlockSize( bs );
00284   }
00285 
00287   // Setup the state storage.
00288   template <class ScalarType, class MV, class OP>
00289   void BlockCGIter<ScalarType,MV,OP>::setStateSize ()
00290   {
00291     if (!stateStorageInitialized_) {
00292 
00293       // Check if there is any multivector to clone from.
00294       Teuchos::RCP<const MV> lhsMV = lp_->getLHS();
00295       Teuchos::RCP<const MV> rhsMV = lp_->getRHS();
00296       if (lhsMV == Teuchos::null && rhsMV == Teuchos::null) {
00297   stateStorageInitialized_ = false;
00298   return;
00299       }
00300       else {
00301   
00302   // Initialize the state storage
00303   // If the subspace has not be initialized before, generate it using the LHS or RHS from lp_.
00304   if (R_ == Teuchos::null || MVT::GetNumberVecs(*R_)!=blockSize_) {
00305     // Get the multivector that is not null.
00306     Teuchos::RCP<const MV> tmp = ( (rhsMV!=Teuchos::null)? rhsMV: lhsMV );
00307     TEST_FOR_EXCEPTION(tmp == Teuchos::null,std::invalid_argument,
00308            "Belos::BlockCGIter::setStateSize(): linear problem does not specify multivectors to clone from.");
00309     R_ = MVT::Clone( *tmp, blockSize_ );
00310     Z_ = MVT::Clone( *tmp, blockSize_ );
00311     P_ = MVT::Clone( *tmp, blockSize_ );
00312     AP_ = MVT::Clone( *tmp, blockSize_ );
00313   }
00314   
00315   // State storage has now been initialized.
00316   stateStorageInitialized_ = true;
00317       }
00318     }
00319   }
00320 
00322   // Set the block size and make necessary adjustments.
00323   template <class ScalarType, class MV, class OP>
00324   void BlockCGIter<ScalarType,MV,OP>::setBlockSize (int blockSize)
00325   {
00326     // This routine only allocates space; it doesn't not perform any computation
00327     // any change in size will invalidate the state of the solver.
00328 
00329     TEST_FOR_EXCEPTION(blockSize <= 0, std::invalid_argument, "Belos::BlockGmresIter::setBlockSize was passed a non-positive argument.");
00330     if (blockSize == blockSize_) {
00331       // do nothing
00332       return;
00333     }
00334 
00335     if (blockSize!=blockSize_)
00336       stateStorageInitialized_ = false;
00337 
00338     blockSize_ = blockSize;
00339 
00340     initialized_ = false;
00341 
00342     // Use the current blockSize_ to initialize the state storage.
00343     setStateSize();
00344 
00345   }
00346 
00348   // Initialize this iteration object
00349   template <class ScalarType, class MV, class OP>
00350   void BlockCGIter<ScalarType,MV,OP>::initializeCG(CGIterationState<ScalarType,MV> newstate)
00351   {
00352     // Initialize the state storage if it isn't already.
00353     if (!stateStorageInitialized_) 
00354       setStateSize();
00355 
00356     TEST_FOR_EXCEPTION(!stateStorageInitialized_,std::invalid_argument,
00357            "Belos::BlockCGIter::initialize(): Cannot initialize state storage!");
00358     
00359     // NOTE:  In BlockCGIter R_, the initial residual, is required!!!  
00360     //
00361     std::string errstr("Belos::BlockCGIter::initialize(): Specified multivectors must have a consistent length and width.");
00362 
00363     // Create convenience variables for zero and one.
00364     const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
00365     const MagnitudeType zero = Teuchos::ScalarTraits<MagnitudeType>::zero();
00366 
00367     if (newstate.R != Teuchos::null) {
00368 
00369       TEST_FOR_EXCEPTION( MVT::GetVecLength(*newstate.R) != MVT::GetVecLength(*R_),
00370                           std::invalid_argument, errstr );
00371       TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*newstate.R) != blockSize_,
00372                           std::invalid_argument, errstr );
00373 
00374       // Copy basis vectors from newstate into V
00375       if (newstate.R != R_) {
00376         // copy over the initial residual (unpreconditioned).
00377   MVT::MvAddMv( one, *newstate.R, zero, *newstate.R, *R_ );
00378       }
00379       // Compute initial direction vectors
00380       // Initially, they are set to the preconditioned residuals
00381       //
00382       if ( lp_->getLeftPrec() != Teuchos::null ) {
00383   lp_->applyLeftPrec( *R_, *Z_ ); 
00384   MVT::MvAddMv( one, *Z_, zero, *Z_, *P_ );
00385       } else {
00386   Z_ = R_;
00387   MVT::MvAddMv( one, *R_, zero, *R_, *P_ );
00388       }
00389     }
00390     else {
00391 
00392       TEST_FOR_EXCEPTION(newstate.R == Teuchos::null,std::invalid_argument,
00393                          "Belos::BlockCGIter::initialize(): BlockCGStateIterState does not have initial residual.");
00394     }
00395 
00396     // The solver is initialized
00397     initialized_ = true;
00398   }
00399 
00400 
00402   // Iterate until the status test informs us we should stop.
00403   template <class ScalarType, class MV, class OP>
00404   void BlockCGIter<ScalarType,MV,OP>::iterate()
00405   {
00406     //
00407     // Allocate/initialize data structures
00408     //
00409     if (initialized_ == false) {
00410       initialize();
00411     }
00412     // Allocate data needed for LAPACK work.
00413     int info = 0;
00414     char UPLO = 'U';
00415     Teuchos::LAPACK<int,ScalarType> lapack;
00416 
00417     // Allocate memory for scalars.
00418     Teuchos::SerialDenseMatrix<int,ScalarType> alpha( blockSize_, blockSize_ );
00419     Teuchos::SerialDenseMatrix<int,ScalarType> beta( blockSize_, blockSize_ );
00420     Teuchos::SerialDenseMatrix<int,ScalarType> rHz( blockSize_, blockSize_ ), 
00421       rHz_old( blockSize_, blockSize_ ), pAp( blockSize_, blockSize_ );
00422 
00423     // Create convenience variables for zero and one.
00424     const ScalarType one = Teuchos::ScalarTraits<ScalarType>::one();
00425     
00426     // Get the current solution std::vector.
00427     Teuchos::RCP<MV> cur_soln_vec = lp_->getCurrLHSVec();
00428 
00429     // Check that the current solution std::vector has blockSize_ columns. 
00430     TEST_FOR_EXCEPTION( MVT::GetNumberVecs(*cur_soln_vec) != blockSize_, CGIterateFailure,
00431                         "Belos::BlockCGIter::iterate(): current linear system does not have the right number of vectors!" );
00432     int rank = ortho_->normalize( *P_, Teuchos::null );
00433     TEST_FOR_EXCEPTION(rank != blockSize_,CGIterationOrthoFailure,
00434                          "Belos::BlockCGIter::iterate(): Failed to compute initial block of orthonormal direction vectors.");
00435 
00436 
00438     // Iterate until the status test tells us to stop.
00439     //
00440     while (stest_->checkStatus(this) != Passed) {
00441         
00442       // Increment the iteration
00443       iter_++;
00444     
00445       // Multiply the current direction std::vector by A and store in Ap_
00446       lp_->applyOp( *P_, *AP_ );
00447       
00448       // Compute alpha := <P_,R_> / <P_,AP_>
00449       // 1) Compute P^T * A * P = pAp and P^T * R 
00450       // 2) Compute the Cholesky Factorization of pAp
00451       // 3) Back and forward solves to compute alpha
00452       //
00453       MVT::MvTransMv( one, *P_, *R_, alpha );
00454       MVT::MvTransMv( one, *P_, *AP_, pAp );      
00455      
00456       // Compute Cholesky factorization of pAp
00457       lapack.POTRF(UPLO, blockSize_, pAp.values(), blockSize_, &info);
00458       TEST_FOR_EXCEPTION(info != 0,CGIterationLAPACKFailure,
00459                          "Belos::BlockCGIter::iterate(): Failed to compute Cholesky factorization using LAPACK routine POTRF.");
00460 
00461       // Compute alpha by performing a back and forward solve with the Cholesky factorization in pAp.
00462       lapack.POTRS(UPLO, blockSize_, blockSize_, pAp.values(), blockSize_, 
00463        alpha.values(), blockSize_, &info);
00464       TEST_FOR_EXCEPTION(info != 0,CGIterationLAPACKFailure,
00465                          "Belos::BlockCGIter::iterate(): Failed to compute alpha using Cholesky factorization (POTRS).");
00466       
00467       //
00468       // Update the solution std::vector X := X + alpha * P_
00469       //
00470       MVT::MvTimesMatAddMv( one, *P_, alpha, one, *cur_soln_vec );
00471       lp_->updateSolution();
00472       //
00473       // Compute the new residual R_ := R_ - alpha * AP_
00474       //
00475       MVT::MvTimesMatAddMv( -one, *AP_, alpha, one, *R_ );
00476       //
00477       // Compute the new preconditioned residual, Z_.
00478       if ( lp_->getLeftPrec() != Teuchos::null ) {
00479   lp_->applyLeftPrec( *R_, *Z_ );
00480       } else {
00481   Z_ = R_;
00482       }
00483       //
00484       // Compute beta := <AP_,Z_> / <P_,AP_> 
00485       // 1) Compute AP_^T * Z_ 
00486       // 2) Compute the Cholesky Factorization of pAp (already have)
00487       // 3) Back and forward solves to compute beta
00488 
00489       // Compute <AP_,Z>
00490       MVT::MvTransMv( -one, *AP_, *Z_, beta );
00491       //
00492       lapack.POTRS(UPLO, blockSize_, blockSize_, pAp.values(), blockSize_, 
00493        beta.values(), blockSize_, &info);
00494       TEST_FOR_EXCEPTION(info != 0,CGIterationLAPACKFailure,
00495                          "Belos::BlockCGIter::iterate(): Failed to compute beta using Cholesky factorization (POTRS).");
00496       //
00497       // Compute the new direction vectors P_ = Z_ + P_ * beta 
00498       //
00499       Teuchos::RCP<MV> Pnew = MVT::CloneCopy( *Z_ );
00500       MVT::MvTimesMatAddMv(one, *P_, beta, one, *Pnew);
00501       P_ = Pnew;
00502 
00503       // Compute orthonormal block of new direction vectors.
00504       rank = ortho_->normalize( *P_, Teuchos::null );
00505       TEST_FOR_EXCEPTION(rank != blockSize_,CGIterationOrthoFailure,
00506                          "Belos::BlockCGIter::iterate(): Failed to compute block of orthonormal direction vectors.");
00507       
00508     } // end while (sTest_->checkStatus(this) != Passed)
00509   }
00510 
00511 } // end Belos namespace
00512 
00513 #endif /* BELOS_BLOCK_CG_ITER_HPP */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines