IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_Krylov.cpp
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) 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 // 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 
00043 #include "Ifpack_ConfigDefs.h"
00044 #include <iomanip>
00045 #include "Epetra_Operator.h"
00046 #include "Epetra_RowMatrix.h"
00047 #include "Epetra_Comm.h"
00048 #include "Epetra_Map.h"
00049 #include "Epetra_MultiVector.h"
00050 #include "Epetra_Vector.h"
00051 #include "Epetra_Time.h"
00052 #include "Ifpack_Krylov.h"
00053 #include "Ifpack_Utils.h"
00054 #include "Ifpack_Condest.h"
00055 #ifdef HAVE_IFPACK_AZTECOO
00056 #include "AztecOO.h"
00057 #endif
00058 
00059 #ifdef HAVE_IFPACK_EPETRAEXT
00060 #include "Epetra_CrsMatrix.h"
00061 #include "EpetraExt_PointToBlockDiagPermute.h"
00062 #endif
00063 
00064 //==============================================================================
00065 // NOTE: any change to the default values should be committed to the other
00066 //       constructor as well.
00067 Ifpack_Krylov::
00068 Ifpack_Krylov(Epetra_Operator* Operator) :
00069   IsInitialized_(false),
00070   IsComputed_(false),
00071   NumInitialize_(0),
00072   NumCompute_(0),
00073   NumApplyInverse_(0),
00074   InitializeTime_(0.0),
00075   ComputeTime_(0.0),
00076   ApplyInverseTime_(0.0),
00077   ComputeFlops_(0.0),
00078   ApplyInverseFlops_(0.0),
00079   Iterations_(5),
00080   Tolerance_(1e-6),
00081   SolverType_(1),
00082   PreconditionerType_(1),
00083   NumSweeps_(0),
00084   BlockSize_(1),
00085   DampingParameter_(1.0),
00086   UseTranspose_(false),
00087   Condest_(-1.0),
00088   ComputeCondest_(false),
00089   Label_(),
00090   NumMyRows_(0),
00091   NumMyNonzeros_(0),
00092   NumGlobalRows_(0),
00093   NumGlobalNonzeros_(0),
00094   Operator_(Teuchos::rcp(Operator,false)),
00095   IsRowMatrix_(false), 
00096   ZeroStartingSolution_(true)
00097 {
00098 }
00099 
00100 //==============================================================================
00101 // NOTE: This constructor has been introduced because SWIG does not appear
00102 //       to appreciate dynamic_cast. An instruction of type
00103 //       Matrix_ = dynamic_cast<const Epetra_RowMatrix*> in the
00104 //       other construction does not work in PyTrilinos -- of course
00105 //       it does in any C++ code (for an Epetra_Operator that is also
00106 //       an Epetra_RowMatrix).
00107 //
00108 // FIXME: move declarations into a separate method?
00109 Ifpack_Krylov::
00110 Ifpack_Krylov(Epetra_RowMatrix* Operator) :
00111   IsInitialized_(false),
00112   IsComputed_(false),
00113   NumInitialize_(0),
00114   NumCompute_(0),
00115   NumApplyInverse_(0),
00116   InitializeTime_(0.0),
00117   ComputeTime_(0.0),
00118   ApplyInverseTime_(0.0),
00119   ComputeFlops_(0.0),
00120   ApplyInverseFlops_(0.0),
00121   Iterations_(5),
00122   Tolerance_(1e-6),
00123   SolverType_(1),
00124   PreconditionerType_(1),
00125   NumSweeps_(0),
00126   BlockSize_(1),
00127   DampingParameter_(1.0),
00128   UseTranspose_(false),
00129   Condest_(-1.0),
00130   ComputeCondest_(false),
00131   Label_(),
00132   NumMyRows_(0),
00133   NumMyNonzeros_(0),
00134   NumGlobalRows_(0),
00135   NumGlobalNonzeros_(0),
00136   Operator_(Teuchos::rcp(Operator,false)),
00137   Matrix_(Teuchos::rcp(Operator,false)),
00138   IsRowMatrix_(true), 
00139   ZeroStartingSolution_(true)
00140 {
00141 }
00142 
00143 //==============================================================================
00144 int Ifpack_Krylov::SetParameters(Teuchos::ParameterList& List)
00145 {
00146   Iterations_           = List.get("krylov: iterations",Iterations_);
00147   Tolerance_            = List.get("krylov: tolerance",Tolerance_);
00148   SolverType_           = List.get("krylov: solver",SolverType_);
00149   PreconditionerType_   = List.get("krylov: preconditioner",PreconditionerType_);
00150   NumSweeps_            = List.get("krylov: number of sweeps",NumSweeps_);
00151   BlockSize_            = List.get("krylov: block size",BlockSize_);
00152   DampingParameter_     = List.get("krylov: damping parameter",DampingParameter_);
00153   ZeroStartingSolution_ = List.get("krylov: zero starting solution",ZeroStartingSolution_);
00154   SetLabel();
00155   return(0);
00156 }
00157 
00158 //==============================================================================
00159 const Epetra_Comm& Ifpack_Krylov::Comm() const
00160 {
00161   return(Operator_->Comm());
00162 }
00163 
00164 //==============================================================================
00165 const Epetra_Map& Ifpack_Krylov::OperatorDomainMap() const
00166 {
00167   return(Operator_->OperatorDomainMap());
00168 }
00169 
00170 //==============================================================================
00171 const Epetra_Map& Ifpack_Krylov::OperatorRangeMap() const
00172 {
00173   return(Operator_->OperatorRangeMap());
00174 }
00175 
00176 //==============================================================================
00177 int Ifpack_Krylov::
00178 Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00179 {
00180   if (IsComputed() == false)
00181     IFPACK_CHK_ERR(-3);
00182 
00183   if (X.NumVectors() != Y.NumVectors())
00184     IFPACK_CHK_ERR(-2);
00185 
00186   if (IsRowMatrix_)
00187   {
00188     IFPACK_CHK_ERR(Matrix_->Multiply(UseTranspose(),X,Y));
00189   }
00190   else
00191   {
00192     IFPACK_CHK_ERR(Operator_->Apply(X,Y));
00193   }
00194 
00195   return(0);
00196 }
00197 
00198 //==============================================================================
00199 int Ifpack_Krylov::Initialize()
00200 {
00201   IsInitialized_ = false;
00202 
00203   if (Operator_ == Teuchos::null)
00204     IFPACK_CHK_ERR(-2);
00205 
00206   if (Time_ == Teuchos::null)
00207     Time_ = Teuchos::rcp( new Epetra_Time(Comm()) );
00208 
00209   if (IsRowMatrix_)
00210   {
00211     if (Matrix().NumGlobalRows64() != Matrix().NumGlobalCols64())
00212       IFPACK_CHK_ERR(-2); // only square matrices
00213 
00214     NumMyRows_ = Matrix_->NumMyRows();
00215     NumMyNonzeros_ = Matrix_->NumMyNonzeros();
00216     NumGlobalRows_ = Matrix_->NumGlobalRows64();
00217     NumGlobalNonzeros_ = Matrix_->NumGlobalNonzeros64();
00218   }
00219   else
00220   {
00221     if (Operator_->OperatorDomainMap().NumGlobalElements64() !=       
00222         Operator_->OperatorRangeMap().NumGlobalElements64())
00223       IFPACK_CHK_ERR(-2); // only square operators
00224   }
00225   
00226   ++NumInitialize_;
00227   InitializeTime_ += Time_->ElapsedTime();
00228   IsInitialized_ = true;
00229   return(0);
00230 }
00231 
00232 //==============================================================================
00233 int Ifpack_Krylov::Compute()
00234 {
00235   if (!IsInitialized())
00236     IFPACK_CHK_ERR(Initialize());
00237 
00238   Time_->ResetStartTime();
00239 
00240 #ifdef HAVE_IFPACK_AZTECOO
00241   // setup Aztec solver
00242   AztecSolver_ = Teuchos::rcp( new AztecOO );
00243   if(IsRowMatrix_==true) {
00244     AztecSolver_ -> SetUserMatrix(&*Matrix_);
00245   }
00246   else {
00247     AztecSolver_ -> SetUserOperator(&*Operator_);
00248   }
00249   if(SolverType_==0) {
00250     AztecSolver_ -> SetAztecOption(AZ_solver, AZ_cg);
00251   }
00252   else {
00253     AztecSolver_ -> SetAztecOption(AZ_solver, AZ_gmres);
00254   }
00255   AztecSolver_ -> SetAztecOption(AZ_output, AZ_none);
00256   // setup preconditioner
00257   Teuchos::ParameterList List;
00258   List.set("relaxation: damping factor", DampingParameter_);
00259   List.set("relaxation: sweeps",NumSweeps_);
00260   if(PreconditionerType_==0)      { }
00261   else if(PreconditionerType_==1) { List.set("relaxation: type", "Jacobi"                ); }
00262   else if(PreconditionerType_==2) { List.set("relaxation: type", "Gauss-Seidel"          ); }
00263   else if(PreconditionerType_==3) { List.set("relaxation: type", "symmetric Gauss-Seidel"); }
00264   if(BlockSize_==1) {
00265     IfpackPrec_ = Teuchos::rcp( new Ifpack_PointRelaxation(&*Matrix_) );
00266   }
00267   else {
00268     IfpackPrec_ = Teuchos::rcp( new Ifpack_BlockRelaxation< Ifpack_DenseContainer > (&*Matrix_) );
00269     int NumRows;
00270     if(IsRowMatrix_==true) {
00271       NumRows = Matrix_->NumMyRows();
00272     }
00273     else {
00274       long long NumRows_LL = Operator_->OperatorDomainMap().NumGlobalElements64();
00275       if(NumRows_LL > std::numeric_limits<int>::max())
00276         throw "Ifpack_Krylov::Compute: NumGlobalElements don't fit an int";
00277       else
00278         NumRows = static_cast<int>(NumRows_LL);
00279     }
00280     List.set("partitioner: type", "linear");
00281     List.set("partitioner: local parts", NumRows/BlockSize_);
00282   }
00283   if(PreconditionerType_>0) {
00284     IfpackPrec_ -> SetParameters(List);
00285     IfpackPrec_ -> Initialize();
00286     IfpackPrec_ -> Compute();
00287     AztecSolver_ -> SetPrecOperator(&*IfpackPrec_);
00288   }
00289 #else
00290   cout << "You need to configure IFPACK with support for AztecOO" << endl;
00291   cout << "to use this preconditioner. This may require --enable-aztecoo" << endl;
00292   cout << "in your configure script." << endl;
00293   IFPACK_CHK_ERR(-1);
00294 #endif
00295 
00296   // reset values
00297   IsComputed_ = false;
00298   Condest_ = -1.0;
00299   ++NumCompute_;
00300   ComputeTime_ += Time_->ElapsedTime();
00301   IsComputed_ = true;
00302 
00303   return(0);
00304 }
00305 
00306 //==============================================================================
00307 ostream& Ifpack_Krylov::Print(ostream & os) const
00308 {
00309 
00310   if (!Comm().MyPID()) {
00311     os << endl;
00312     os << "================================================================================" << endl;
00313     os << "Ifpack_Krylov" << endl;
00314     os << "Number of iterations                 = " << Iterations_ << endl;
00315     os << "Residual Tolerance                   = " << Tolerance_ << endl;
00316     os << "Solver type (O for CG, 1 for GMRES)  = " << SolverType_ << endl;
00317     os << "Preconditioner type                  = " << PreconditionerType_ << endl;
00318     os << "(0 for none, 1 for Jacobi, 2 for GS, 3 for SGS )" << endl;
00319     os << "Condition number estimate            = " << Condest() << endl;
00320     os << "Global number of rows                = " << Operator_->OperatorRangeMap().NumGlobalElements64() << endl;
00321     if (ZeroStartingSolution_) 
00322       os << "Using zero starting solution" << endl;
00323     else
00324       os << "Using input starting solution" << endl;
00325     os << endl;
00326     os << "Phase           # calls   Total Time (s)       Total MFlops     MFlops/s" << endl;
00327     os << "-----           -------   --------------       ------------     --------" << endl;
00328     os << "Initialize()    "   << std::setw(5) << NumInitialize_ 
00329        << "  " << std::setw(15) << InitializeTime_ 
00330        << "              0.0              0.0" << endl;
00331     os << "Compute()       "   << std::setw(5) << NumCompute_ 
00332        << "  " << std::setw(15) << ComputeTime_
00333        << "  " << std::setw(15) << 1.0e-6 * ComputeFlops_;
00334     if (ComputeTime_ != 0.0)
00335       os << "  " << std::setw(15) << 1.0e-6 * ComputeFlops_ / ComputeTime_ << endl;
00336     else
00337       os << "  " << std::setw(15) << 0.0 << endl;
00338     os << "ApplyInverse()  "   << std::setw(5) << NumApplyInverse_ 
00339        << "  " << std::setw(15) << ApplyInverseTime_
00340        << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops_;
00341     if (ApplyInverseTime_ != 0.0)
00342       os << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops_ / ApplyInverseTime_ << endl;
00343     else
00344       os << "  " << std::setw(15) << 0.0 << endl;
00345     os << "================================================================================" << endl;
00346     os << endl;
00347   }
00348 
00349   return(os);
00350 }
00351 
00352 //==============================================================================
00353 double Ifpack_Krylov::
00354 Condest(const Ifpack_CondestType CT, 
00355         const int MaxIters, const double Tol,
00356     Epetra_RowMatrix* Matrix_in)
00357 {
00358   if (!IsComputed()) // cannot compute right now
00359     return(-1.0);
00360 
00361   // always computes it. Call Condest() with no parameters to get
00362   // the previous estimate.
00363   Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00364 
00365   return(Condest_);
00366 }
00367 
00368 //==============================================================================
00369 void Ifpack_Krylov::SetLabel()
00370 {
00371   Label_ = "IFPACK (Krylov smoother), iterations=" + Ifpack_toString(Iterations_);
00372 }
00373 
00374 //==============================================================================
00375 int Ifpack_Krylov::
00376 ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00377 {
00378   
00379   if (!IsComputed())
00380     IFPACK_CHK_ERR(-3);
00381 
00382   if (Iterations_ == 0)
00383     return 0;
00384 
00385   int nVec = X.NumVectors();
00386   if (nVec != Y.NumVectors())
00387     IFPACK_CHK_ERR(-2);
00388 
00389   Time_->ResetStartTime();
00390 
00391   // AztecOO gives X and Y pointing to the same memory location,
00392   // need to create an auxiliary vector, Xcopy
00393   Teuchos::RCP<Epetra_MultiVector> Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) );
00394   if(ZeroStartingSolution_==true) {
00395     Y.PutScalar(0.0);
00396   }
00397 
00398 #ifdef HAVE_IFPACK_AZTECOO
00399   AztecSolver_ -> SetLHS(&Y);
00400   AztecSolver_ -> SetRHS(&*Xcopy);
00401   AztecSolver_ -> Iterate(Iterations_,Tolerance_);
00402 #else
00403   cout << "You need to configure IFPACK with support for AztecOO" << endl;
00404   cout << "to use this preconditioner. This may require --enable-aztecoo" << endl;
00405   cout << "in your configure script." << endl;
00406   IFPACK_CHK_ERR(-1);
00407 #endif
00408 
00409   // Flops are updated in each of the following. 
00410   ++NumApplyInverse_;
00411   ApplyInverseTime_ += Time_->ElapsedTime();
00412   return(0);
00413 }
 All Classes Files Functions Variables Enumerations Friends