IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_Polynomial.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_Polynomial.h"
00053 #include "Ifpack_Utils.h"
00054 #include "Ifpack_Condest.h"
00055 #include "Teuchos_LAPACK.hpp"
00056 #include "Teuchos_SerialDenseMatrix.hpp"
00057 #include <complex>
00058 #ifdef HAVE_IFPACK_AZTECOO
00059 #include "Ifpack_DiagPreconditioner.h"
00060 #include "AztecOO.h"
00061 #endif
00062 
00063 #ifdef HAVE_IFPACK_EPETRAEXT
00064 #include "Epetra_CrsMatrix.h"
00065 #include "EpetraExt_PointToBlockDiagPermute.h"
00066 #endif
00067 
00068 
00069 #define ABS(x) ((x)>0?(x):-(x))
00070 
00071 // Helper function for normal equations
00072 inline void Apply_Transpose(Teuchos::RCP<const Epetra_Operator> Operator_,const Epetra_MultiVector &X,Epetra_MultiVector &Y){
00073   Epetra_Operator * Operator=const_cast<Epetra_Operator*>(&*Operator_);
00074   Operator->SetUseTranspose(true);
00075   Operator->Apply(X,Y);
00076   Operator->SetUseTranspose(false);
00077 }
00078 
00079 
00080 
00081 
00082 //==============================================================================
00083 // NOTE: any change to the default values should be committed to the other
00084 //       constructor as well.
00085 Ifpack_Polynomial::
00086 Ifpack_Polynomial(const Epetra_Operator* Operator) :
00087   IsInitialized_(false),
00088   IsComputed_(false),
00089   IsIndefinite_(false),
00090   IsComplex_(false),
00091   NumInitialize_(0),
00092   NumCompute_(0),
00093   NumApplyInverse_(0),
00094   InitializeTime_(0.0),
00095   ComputeTime_(0.0),
00096   ApplyInverseTime_(0.0),
00097   ComputeFlops_(0.0),
00098   ApplyInverseFlops_(0.0),
00099   PolyDegree_(3),
00100   LSPointsReal_(10),
00101   LSPointsImag_(10),
00102   UseTranspose_(false),
00103   Condest_(-1.0),
00104   ComputeCondest_(false),
00105   RealEigRatio_(10.0),
00106   ImagEigRatio_(10.0),
00107   Label_(),
00108   LambdaRealMin_(0.0),
00109   LambdaRealMax_(-1.0),
00110   LambdaImagMin_(0.0),
00111   LambdaImagMax_(0.0),
00112   MinDiagonalValue_(0.0),
00113   NumMyRows_(0),
00114   NumMyNonzeros_(0),
00115   NumGlobalRows_(0),
00116   NumGlobalNonzeros_(0),
00117   Operator_(Teuchos::rcp(Operator,false)),
00118   UseBlockMode_(false),
00119   SolveNormalEquations_(false),
00120   IsRowMatrix_(false),
00121   ZeroStartingSolution_(true)
00122 {
00123 }
00124 
00125 //==============================================================================
00126 // NOTE: This constructor has been introduced because SWIG does not appear
00127 //       to appreciate dynamic_cast. An instruction of type
00128 //       Matrix_ = dynamic_cast<const Epetra_RowMatrix*> in the
00129 //       other construction does not work in PyTrilinos -- of course
00130 //       it does in any C++ code (for an Epetra_Operator that is also
00131 //       an Epetra_RowMatrix).
00132 //
00133 // FIXME: move declarations into a separate method?
00134 Ifpack_Polynomial::
00135 Ifpack_Polynomial(const Epetra_RowMatrix* Operator) :
00136   IsInitialized_(false),
00137   IsComputed_(false),
00138   IsIndefinite_(false),
00139   IsComplex_(false),
00140   NumInitialize_(0),
00141   NumCompute_(0),
00142   NumApplyInverse_(0),
00143   InitializeTime_(0.0),
00144   ComputeTime_(0.0),
00145   ApplyInverseTime_(0.0),
00146   ComputeFlops_(0.0),
00147   ApplyInverseFlops_(0.0),
00148   PolyDegree_(3),
00149   LSPointsReal_(10),
00150   LSPointsImag_(10),
00151   UseTranspose_(false),
00152   Condest_(-1.0),
00153   ComputeCondest_(false),
00154   RealEigRatio_(10.0),
00155   ImagEigRatio_(10.0),
00156   EigMaxIters_(10),
00157   Label_(),
00158   LambdaRealMin_(0.0),
00159   LambdaRealMax_(-1.0),
00160   LambdaImagMin_(0.0),
00161   LambdaImagMax_(0.0),
00162   MinDiagonalValue_(0.0),
00163   NumMyRows_(0),
00164   NumMyNonzeros_(0),
00165   NumGlobalRows_(0),
00166   NumGlobalNonzeros_(0),
00167   Operator_(Teuchos::rcp(Operator,false)),
00168   Matrix_(Teuchos::rcp(Operator,false)),
00169   UseBlockMode_(false),
00170   SolveNormalEquations_(false),
00171   IsRowMatrix_(true),
00172   ZeroStartingSolution_(true)
00173 {
00174 }
00175 
00176 //==============================================================================
00177 int Ifpack_Polynomial::SetParameters(Teuchos::ParameterList& List)
00178 {
00179 
00180   RealEigRatio_         = List.get("polynomial: real eigenvalue ratio", RealEigRatio_);
00181   ImagEigRatio_         = List.get("polynomial: imag eigenvalue ratio", ImagEigRatio_);
00182   LambdaRealMin_        = List.get("polynomial: min real part", LambdaRealMin_);
00183   LambdaRealMax_        = List.get("polynomial: max real part", LambdaRealMax_);
00184   LambdaImagMin_        = List.get("polynomial: min imag part", LambdaImagMin_);
00185   LambdaImagMax_        = List.get("polynomial: max imag part", LambdaImagMax_);
00186   PolyDegree_           = List.get("polynomial: degree",PolyDegree_);
00187   LSPointsReal_         = List.get("polynomial: real interp points",LSPointsReal_);
00188   LSPointsImag_         = List.get("polynomial: imag interp points",LSPointsImag_);
00189   IsIndefinite_         = List.get("polynomial: indefinite",IsIndefinite_);
00190   IsComplex_            = List.get("polynomial: complex",IsComplex_);
00191   MinDiagonalValue_     = List.get("polynomial: min diagonal value",
00192                                    MinDiagonalValue_);
00193   ZeroStartingSolution_ = List.get("polynomial: zero starting solution",
00194                                    ZeroStartingSolution_);
00195 
00196   Epetra_Vector* ID     = List.get("polynomial: operator inv diagonal",
00197                                    (Epetra_Vector*)0);
00198   EigMaxIters_          = List.get("polynomial: eigenvalue max iterations",EigMaxIters_);
00199 
00200 #ifdef HAVE_IFPACK_EPETRAEXT
00201   // This is *always* false if EpetraExt isn't enabled
00202   UseBlockMode_         = List.get("polynomial: use block mode",UseBlockMode_);
00203   if(!List.isParameter("polynomial: block list")) UseBlockMode_=false;
00204   else{
00205     BlockList_          = List.get("polynomial: block list",BlockList_);
00206 
00207     // Since we know we're doing a matrix inverse, clobber the block list
00208     // w/"invert" if it's set to multiply
00209     Teuchos::ParameterList Blist;
00210     Blist=BlockList_.get("blockdiagmatrix: list",Blist);
00211     string dummy("invert");
00212     string ApplyMode=Blist.get("apply mode",dummy);
00213     if(ApplyMode==string("multiply")){
00214       Blist.set("apply mode","invert");
00215       BlockList_.set("blockdiagmatrix: list",Blist);
00216     }
00217   }
00218 #endif
00219 
00220   SolveNormalEquations_ = List.get("polynomial: solve normal equations",SolveNormalEquations_);
00221 
00222   if (ID != 0)
00223   {
00224     InvDiagonal_ = Teuchos::rcp( new Epetra_Vector(*ID) );
00225   }
00226 
00227   SetLabel();
00228 
00229   return(0);
00230 }
00231 
00232 //==============================================================================
00233 const Epetra_Comm& Ifpack_Polynomial::Comm() const
00234 {
00235   return(Operator_->Comm());
00236 }
00237 
00238 //==============================================================================
00239 const Epetra_Map& Ifpack_Polynomial::OperatorDomainMap() const
00240 {
00241   return(Operator_->OperatorDomainMap());
00242 }
00243 
00244 //==============================================================================
00245 const Epetra_Map& Ifpack_Polynomial::OperatorRangeMap() const
00246 {
00247   return(Operator_->OperatorRangeMap());
00248 }
00249 
00250 //==============================================================================
00251 int Ifpack_Polynomial::
00252 Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00253 {
00254   if (IsComputed() == false)
00255     IFPACK_CHK_ERR(-3);
00256 
00257   if (X.NumVectors() != Y.NumVectors())
00258     IFPACK_CHK_ERR(-2);
00259 
00260   if (IsRowMatrix_)
00261   {
00262     IFPACK_CHK_ERR(Matrix_->Multiply(UseTranspose(),X,Y));
00263   }
00264   else
00265   {
00266     IFPACK_CHK_ERR(Operator_->Apply(X,Y));
00267   }
00268 
00269   return(0);
00270 }
00271 
00272 //==============================================================================
00273 int Ifpack_Polynomial::Initialize()
00274 {
00275   IsInitialized_ = false;
00276 
00277   if (Operator_ == Teuchos::null)
00278     IFPACK_CHK_ERR(-2);
00279 
00280   if (Time_ == Teuchos::null)
00281     Time_ = Teuchos::rcp( new Epetra_Time(Comm()) );
00282 
00283   if (IsRowMatrix_)
00284   {
00285     if (Matrix().NumGlobalRows64() != Matrix().NumGlobalCols64())
00286       IFPACK_CHK_ERR(-2); // only square matrices
00287 
00288     NumMyRows_ = Matrix_->NumMyRows();
00289     NumMyNonzeros_ = Matrix_->NumMyNonzeros();
00290     NumGlobalRows_ = Matrix_->NumGlobalRows64();
00291     NumGlobalNonzeros_ = Matrix_->NumGlobalNonzeros64();
00292   }
00293   else
00294   {
00295     if (Operator_->OperatorDomainMap().NumGlobalElements64() !=
00296         Operator_->OperatorRangeMap().NumGlobalElements64())
00297       IFPACK_CHK_ERR(-2); // only square operators
00298   }
00299 
00300   ++NumInitialize_;
00301   InitializeTime_ += Time_->ElapsedTime();
00302   IsInitialized_ = true;
00303   return(0);
00304 }
00305 
00306 //==============================================================================
00307 int Ifpack_Polynomial::Compute()
00308 {
00309   if (!IsInitialized())
00310     IFPACK_CHK_ERR(Initialize());
00311 
00312   Time_->ResetStartTime();
00313 
00314   // reset values
00315   IsComputed_ = false;
00316   Condest_ = -1.0;
00317 
00318   if (PolyDegree_ <= 0)
00319     IFPACK_CHK_ERR(-2); // at least one application
00320 
00321 #ifdef HAVE_IFPACK_EPETRAEXT
00322   // Check to see if we can run in block mode
00323   if(IsRowMatrix_ && InvDiagonal_ == Teuchos::null && UseBlockMode_){
00324     const Epetra_CrsMatrix *CrsMatrix=dynamic_cast<const Epetra_CrsMatrix*>(&*Matrix_);
00325 
00326     // If we don't have CrsMatrix, we can't use the block preconditioner
00327     if(!CrsMatrix) UseBlockMode_=false;
00328     else{
00329       int ierr;
00330       InvBlockDiagonal_=Teuchos::rcp(new EpetraExt_PointToBlockDiagPermute(*CrsMatrix));
00331       if(InvBlockDiagonal_==Teuchos::null) IFPACK_CHK_ERR(-6);
00332 
00333       ierr=InvBlockDiagonal_->SetParameters(BlockList_);
00334       if(ierr) IFPACK_CHK_ERR(-7);
00335 
00336       ierr=InvBlockDiagonal_->Compute();
00337       if(ierr) IFPACK_CHK_ERR(-8);
00338     }
00339   }
00340 #endif
00341   if (IsRowMatrix_ && InvDiagonal_ == Teuchos::null && !UseBlockMode_)
00342   {
00343     InvDiagonal_ = Teuchos::rcp( new Epetra_Vector(Matrix().Map()) );
00344 
00345     if (InvDiagonal_ == Teuchos::null)
00346       IFPACK_CHK_ERR(-5);
00347 
00348     IFPACK_CHK_ERR(Matrix().ExtractDiagonalCopy(*InvDiagonal_));
00349 
00350     // Inverse diagonal elements
00351     // Replace zeros with 1.0
00352     for (int i = 0 ; i < NumMyRows_ ; ++i) {
00353       double diag = (*InvDiagonal_)[i];
00354       if (IFPACK_ABS(diag) < MinDiagonalValue_)
00355         (*InvDiagonal_)[i] = MinDiagonalValue_;
00356       else
00357         (*InvDiagonal_)[i] = 1.0 / diag;
00358     }
00359   }
00360 
00361   // Automatically compute maximum eigenvalue estimate of D^{-1}A if user hasn't provided one
00362   double lambda_real_min, lambda_real_max, lambda_imag_min, lambda_imag_max;
00363   if (LambdaRealMax_ == -1) {
00364     //PowerMethod(Matrix(), *InvDiagonal_, EigMaxIters_, lambda_max);
00365     GMRES(Matrix(), *InvDiagonal_, EigMaxIters_, lambda_real_min, lambda_real_max, lambda_imag_min, lambda_imag_max);
00366     LambdaRealMin_=lambda_real_min;  LambdaImagMin_=lambda_imag_min;
00367     LambdaRealMax_=lambda_real_max;  LambdaImagMax_=lambda_imag_max;
00368     //std::cout<<"LambdaRealMin: "<<LambdaRealMin_<<std::endl;
00369     //std::cout<<"LambdaRealMax: "<<LambdaRealMax_<<std::endl;
00370     //std::cout<<"LambdaImagMin: "<<LambdaImagMin_<<std::endl;
00371     //std::cout<<"LambdaImagMax: "<<LambdaImagMax_<<std::endl;
00372   }
00373 
00374   // find least squares polynomial for (LSPointsReal_*LSPointsImag_) zeros
00375   // on a rectangle in the complex plane defined as
00376   // [LambdaRealMin_,LambdaRealMax_] x [LambdaImagMin_,LambdaImagMax_]
00377 
00378   std::complex<double> zero(0.0,0.0);
00379   std::complex<double> one(1.0,0.0);
00380 
00381   // Compute points in complex plane
00382   double lenx = LambdaRealMax_-LambdaRealMin_;
00383   int      nx = ceil(lenx*((double) LSPointsReal_));
00384   if (nx<2) { nx = 2; }
00385   double   hx = lenx/((double) nx);
00386   std::vector<double> xs;
00387   if(abs(lenx)>1.0e-8) {
00388     for( int pt=0; pt<=nx; pt++ ) {
00389       xs.push_back(hx*pt+LambdaRealMin_);
00390     }
00391   }
00392   else {
00393     xs.push_back(LambdaRealMax_);
00394     nx=1;
00395   }
00396   double leny = LambdaImagMax_-LambdaImagMin_;
00397   int      ny = ceil(leny*((double) LSPointsImag_));
00398   if (ny<2) { ny = 2; }
00399   double   hy = leny/((double) ny);
00400   std::vector<double> ys;
00401   if(abs(leny)>1.0e-8) {
00402     for( int pt=0; pt<=ny; pt++ ) {
00403       ys.push_back(hy*pt+LambdaImagMin_);
00404     }
00405   }
00406   else {
00407     ys.push_back(LambdaImagMax_);
00408     ny=1;
00409   }
00410   std::vector< std::complex<double> > cpts;
00411   for( int jj=0; jj<ny; jj++ ) {
00412     for( int ii=0; ii<nx; ii++ ) {
00413       std::complex<double> cpt(xs[ii],ys[jj]);
00414       cpts.push_back(cpt);
00415     }
00416   }
00417   cpts.push_back(zero);
00418 
00419 #ifdef HAVE_TEUCHOS_COMPLEX
00420 
00421   // Construct overdetermined Vandermonde matrix
00422   Teuchos::SerialDenseMatrix<int, std::complex<double> > Vmatrix(cpts.size(),PolyDegree_+1);
00423   Vmatrix.putScalar(zero);
00424   for (int jj = 0; jj <= PolyDegree_; ++jj) {
00425     for (int ii = 0; ii < static_cast<int> (cpts.size ()) - 1; ++ii) {
00426       if (jj > 0) {
00427         Vmatrix(ii,jj) = pow(cpts[ii],jj);
00428       }
00429       else {
00430         Vmatrix(ii,jj) = one;
00431       }
00432     }
00433   }
00434   Vmatrix(cpts.size()-1,0)=one;
00435 
00436   // Right hand side: all zero except last entry
00437   Teuchos::SerialDenseMatrix< int,std::complex<double> > RHS(cpts.size(),1);
00438   RHS.putScalar(zero);
00439   RHS(cpts.size()-1,0)=one;
00440 
00441   // Solve least squares problem using LAPACK
00442   Teuchos::LAPACK< int, std::complex<double> > lapack;
00443   const int N = Vmatrix.numCols();
00444   Teuchos::Array<double> singularValues(N);
00445   Teuchos::Array<double> rwork(1);
00446   rwork.resize (std::max (1, 5 * N));
00447   std::complex<double> lworkScalar(1.0,0.0);
00448   int info = 0;
00449   lapack.GELS('N', Vmatrix.numRows(), Vmatrix.numCols(), RHS.numCols(),
00450                    Vmatrix.values(),  Vmatrix.numRows(), RHS.values(),    RHS.numRows(),
00451                    &lworkScalar, -1, &info);
00452   TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
00453                              "_GELSS workspace query returned INFO = "
00454                              << info << " != 0.");
00455   const int lwork = static_cast<int> (real(lworkScalar));
00456   TEUCHOS_TEST_FOR_EXCEPTION(lwork < 0, std::logic_error,
00457                              "_GELSS workspace query returned LWORK = "
00458                              << lwork << " < 0.");
00459   // Allocate workspace.  Size > 0 means &work[0] makes sense.
00460   Teuchos::Array< std::complex<double> > work (std::max (1, lwork));
00461   // Solve the least-squares problem.
00462   lapack.GELS('N', Vmatrix.numRows(), Vmatrix.numCols(),  RHS.numCols(),
00463                    Vmatrix.values(),  Vmatrix.numRows(),  RHS.values(),   RHS.numRows(),
00464                    &work[0], lwork, &info);
00465 
00466   coeff_.resize(PolyDegree_+1);
00467   std::complex<double> c0=RHS(0,0);
00468   for(int ii=0; ii<=PolyDegree_; ii++) {
00469     // test that the imaginary part is nonzero
00470     //TEUCHOS_TEST_FOR_EXCEPTION(abs(imag(RHS(ii,0))) > 1e-8, std::logic_error,
00471     //                         "imaginary part of polynomial coefficients is nonzero! coeff = "
00472     //                         << RHS(ii,0));
00473     coeff_[ii]=real(RHS(ii,0)/c0);
00474     //std::cout<<"coeff["<<ii<<"]="<<coeff_[ii]<<std::endl;
00475   }
00476 
00477 #else
00478 
00479   // Construct overdetermined Vandermonde matrix
00480   Teuchos::SerialDenseMatrix< int, double > Vmatrix(xs.size()+1,PolyDegree_+1);
00481   Vmatrix.putScalar(0.0);
00482   for( int jj=0; jj<=PolyDegree_; jj++) {
00483     for( int ii=0; ii<xs.size(); ii++) {
00484       if(jj>0) {
00485         Vmatrix(ii,jj)=pow(xs[ii],jj);
00486       }
00487       else {
00488         Vmatrix(ii,jj)=1.0;
00489       }
00490     }
00491   }
00492   Vmatrix(xs.size(),0)=1.0;
00493 
00494   // Right hand side: all zero except last entry
00495   Teuchos::SerialDenseMatrix< int, double > RHS(xs.size()+1,1);
00496   RHS.putScalar(0.0);
00497   RHS(xs.size(),0)=1.0;
00498 
00499   // Solve least squares problem using LAPACK
00500   Teuchos::LAPACK< int, double > lapack;
00501   const int N = Vmatrix.numCols();
00502   Teuchos::Array<double> singularValues(N);
00503   Teuchos::Array<double> rwork(1);
00504   rwork.resize (std::max (1, 5 * N));
00505   double lworkScalar(1.0);
00506   int info = 0;
00507   lapack.GELS('N', Vmatrix.numRows(), Vmatrix.numCols(), RHS.numCols(),
00508                    Vmatrix.values(),  Vmatrix.numRows(), RHS.values(),    RHS.numRows(),
00509                    &lworkScalar, -1, &info);
00510   TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error,
00511                              "_GELSS workspace query returned INFO = "
00512                              << info << " != 0.");
00513   const int lwork = static_cast<int> (lworkScalar);
00514   TEUCHOS_TEST_FOR_EXCEPTION(lwork < 0, std::logic_error,
00515                              "_GELSS workspace query returned LWORK = "
00516                              << lwork << " < 0.");
00517   // Allocate workspace.  Size > 0 means &work[0] makes sense.
00518   Teuchos::Array< double > work (std::max (1, lwork));
00519   // Solve the least-squares problem.
00520   lapack.GELS('N', Vmatrix.numRows(), Vmatrix.numCols(),  RHS.numCols(),
00521                    Vmatrix.values(),  Vmatrix.numRows(),  RHS.values(),   RHS.numRows(),
00522                    &work[0], lwork, &info);
00523 
00524   coeff_.resize(PolyDegree_+1);
00525   double c0=RHS(0,0);
00526   for(int ii=0; ii<=PolyDegree_; ii++) {
00527     // test that the imaginary part is nonzero
00528     //TEUCHOS_TEST_FOR_EXCEPTION(abs(imag(RHS(ii,0))) > 1e-8, std::logic_error,
00529     //                         "imaginary part of polynomial coefficients is nonzero! coeff = "
00530     //                         << RHS(ii,0));
00531     coeff_[ii]=RHS(ii,0)/c0;
00532   }
00533 
00534 #endif
00535 
00536 #ifdef IFPACK_FLOPCOUNTERS
00537   ComputeFlops_ += NumMyRows_;
00538 #endif
00539 
00540   ++NumCompute_;
00541   ComputeTime_ += Time_->ElapsedTime();
00542   IsComputed_ = true;
00543 
00544   return(0);
00545 }
00546 
00547 //==============================================================================
00548 ostream& Ifpack_Polynomial::Print(ostream & os) const
00549 {
00550 
00551   double MyMinVal, MyMaxVal;
00552   double MinVal, MaxVal;
00553 
00554   if (IsComputed_) {
00555     InvDiagonal_->MinValue(&MyMinVal);
00556     InvDiagonal_->MaxValue(&MyMaxVal);
00557     Comm().MinAll(&MyMinVal,&MinVal,1);
00558     Comm().MinAll(&MyMaxVal,&MaxVal,1);
00559   }
00560 
00561   if (!Comm().MyPID()) {
00562     os << endl;
00563     os << "================================================================================" << endl;
00564     os << "Ifpack_Polynomial" << endl;
00565     os << "Degree of polynomial      = " << PolyDegree_ << endl;
00566     os << "Condition number estimate = " << Condest() << endl;
00567     os << "Global number of rows     = " << Operator_->OperatorRangeMap().NumGlobalElements64() << endl;
00568     if (IsComputed_) {
00569       os << "Minimum value on stored inverse diagonal = " << MinVal << endl;
00570       os << "Maximum value on stored inverse diagonal = " << MaxVal << endl;
00571     }
00572     if (ZeroStartingSolution_)
00573       os << "Using zero starting solution" << endl;
00574     else
00575       os << "Using input starting solution" << endl;
00576     os << endl;
00577     os << "Phase           # calls   Total Time (s)       Total MFlops     MFlops/s" << endl;
00578     os << "-----           -------   --------------       ------------     --------" << endl;
00579     os << "Initialize()    "   << std::setw(5) << NumInitialize_
00580        << "  " << std::setw(15) << InitializeTime_
00581        << "              0.0              0.0" << endl;
00582     os << "Compute()       "   << std::setw(5) << NumCompute_
00583        << "  " << std::setw(15) << ComputeTime_
00584        << "  " << std::setw(15) << 1.0e-6 * ComputeFlops_;
00585     if (ComputeTime_ != 0.0)
00586       os << "  " << std::setw(15) << 1.0e-6 * ComputeFlops_ / ComputeTime_ << endl;
00587     else
00588       os << "  " << std::setw(15) << 0.0 << endl;
00589     os << "ApplyInverse()  "   << std::setw(5) << NumApplyInverse_
00590        << "  " << std::setw(15) << ApplyInverseTime_
00591        << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops_;
00592     if (ApplyInverseTime_ != 0.0)
00593       os << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops_ / ApplyInverseTime_ << endl;
00594     else
00595       os << "  " << std::setw(15) << 0.0 << endl;
00596     os << "================================================================================" << endl;
00597     os << endl;
00598   }
00599 
00600   return(os);
00601 }
00602 
00603 //==============================================================================
00604 double Ifpack_Polynomial::
00605 Condest(const Ifpack_CondestType CT,
00606         const int MaxIters, const double Tol,
00607         Epetra_RowMatrix* Matrix_in)
00608 {
00609   if (!IsComputed()) // cannot compute right now
00610     return(-1.0);
00611 
00612   // always computes it. Call Condest() with no parameters to get
00613   // the previous estimate.
00614   Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00615 
00616   return(Condest_);
00617 }
00618 
00619 //==============================================================================
00620 void Ifpack_Polynomial::SetLabel()
00621 {
00622   Label_ = "IFPACK (Least squares polynomial), degree=" + Ifpack_toString(PolyDegree_);
00623 }
00624 
00625 //==============================================================================
00626 int Ifpack_Polynomial::
00627 ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const
00628 {
00629 
00630   if (!IsComputed())
00631     IFPACK_CHK_ERR(-3);
00632 
00633   if (PolyDegree_ == 0)
00634     return 0;
00635 
00636   int nVec = X.NumVectors();
00637   if (nVec != Y.NumVectors())
00638     IFPACK_CHK_ERR(-2);
00639 
00640   Time_->ResetStartTime();
00641 
00642   Epetra_MultiVector Xcopy(X);
00643   if(ZeroStartingSolution_==true) {
00644     Y.PutScalar(0.0);
00645   }
00646 
00647   // mfh 20 Mar 2014: IBD never gets used, so I'm commenting out the
00648   // following lines of code in order to forestall build warnings.
00649 // #ifdef HAVE_IFPACK_EPETRAEXT
00650 //   EpetraExt_PointToBlockDiagPermute* IBD=0;
00651 //   if (UseBlockMode_) IBD=&*InvBlockDiagonal_;
00652 // #endif
00653 
00654   Y.Update(-coeff_[1], Xcopy, 1.0);
00655   for (int ii = 2; ii < static_cast<int> (coeff_.size ()); ++ii) {
00656     const Epetra_MultiVector V(Xcopy);
00657     Operator_->Apply(V,Xcopy);
00658     Xcopy.Multiply(1.0, *InvDiagonal_, Xcopy, 0.0);
00659     // Update Y
00660     Y.Update(-coeff_[ii], Xcopy, 1.0);
00661   }
00662 
00663   // Flops are updated in each of the following.
00664   ++NumApplyInverse_;
00665   ApplyInverseTime_ += Time_->ElapsedTime();
00666   return(0);
00667 }
00668 
00669 //==============================================================================
00670 int Ifpack_Polynomial::
00671 PowerMethod(const Epetra_Operator& Operator,
00672             const Epetra_Vector& InvPointDiagonal,
00673             const int MaximumIterations,
00674             double& lambda_max)
00675 {
00676   // this is a simple power method
00677   lambda_max = 0.0;
00678   double RQ_top, RQ_bottom, norm;
00679   Epetra_Vector x(Operator.OperatorDomainMap());
00680   Epetra_Vector y(Operator.OperatorRangeMap());
00681   x.Random();
00682   x.Norm2(&norm);
00683   if (norm == 0.0) IFPACK_CHK_ERR(-1);
00684 
00685   x.Scale(1.0 / norm);
00686 
00687   for (int iter = 0; iter < MaximumIterations; ++iter)
00688   {
00689     Operator.Apply(x, y);
00690     IFPACK_CHK_ERR(y.Multiply(1.0, InvPointDiagonal, y, 0.0));
00691     IFPACK_CHK_ERR(y.Dot(x, &RQ_top));
00692     IFPACK_CHK_ERR(x.Dot(x, &RQ_bottom));
00693     lambda_max = RQ_top / RQ_bottom;
00694     IFPACK_CHK_ERR(y.Norm2(&norm));
00695     if (norm == 0.0) IFPACK_CHK_ERR(-1);
00696     IFPACK_CHK_ERR(x.Update(1.0 / norm, y, 0.0));
00697   }
00698 
00699   return(0);
00700 }
00701 
00702 //==============================================================================
00703 int Ifpack_Polynomial::
00704 CG(const Epetra_Operator& Operator,
00705    const Epetra_Vector& InvPointDiagonal,
00706    const int MaximumIterations,
00707    double& lambda_min, double& lambda_max)
00708 {
00709 #ifdef HAVE_IFPACK_AZTECOO
00710   Epetra_Vector x(Operator.OperatorDomainMap());
00711   Epetra_Vector y(Operator.OperatorRangeMap());
00712   x.Random();
00713   y.PutScalar(0.0);
00714 
00715   Epetra_LinearProblem LP(const_cast<Epetra_Operator*>(&Operator), &x, &y);
00716   AztecOO solver(LP);
00717   solver.SetAztecOption(AZ_solver, AZ_cg_condnum);
00718   solver.SetAztecOption(AZ_output, AZ_none);
00719 
00720   Ifpack_DiagPreconditioner diag(Operator.OperatorDomainMap(),
00721                                  Operator.OperatorRangeMap(),
00722                                  InvPointDiagonal);
00723   solver.SetPrecOperator(&diag);
00724   solver.Iterate(MaximumIterations, 1e-10);
00725 
00726   const double* status = solver.GetAztecStatus();
00727 
00728   lambda_min = status[AZ_lambda_min];
00729   lambda_max = status[AZ_lambda_max];
00730 
00731   return(0);
00732 #else
00733   cout << "You need to configure IFPACK with support for AztecOO" << endl;
00734   cout << "to use the CG estimator. This may require --enable-aztecoo" << endl;
00735   cout << "in your configure script." << endl;
00736   IFPACK_CHK_ERR(-1);
00737 #endif
00738 }
00739 
00740 //==============================================================================
00741 #ifdef HAVE_IFPACK_EPETRAEXT
00742 int Ifpack_Polynomial::
00743 PowerMethod(const int MaximumIterations,  double& lambda_max)
00744 {
00745 
00746   if(!UseBlockMode_) IFPACK_CHK_ERR(-1);
00747   // this is a simple power method
00748   lambda_max = 0.0;
00749   double RQ_top, RQ_bottom, norm;
00750   Epetra_Vector x(Operator_->OperatorDomainMap());
00751   Epetra_Vector y(Operator_->OperatorRangeMap());
00752   Epetra_Vector z(Operator_->OperatorRangeMap());
00753   x.Random();
00754   x.Norm2(&norm);
00755   if (norm == 0.0) IFPACK_CHK_ERR(-1);
00756 
00757   x.Scale(1.0 / norm);
00758 
00759   for (int iter = 0; iter < MaximumIterations; ++iter)
00760   {
00761     Operator_->Apply(x, z);
00762     InvBlockDiagonal_->ApplyInverse(z,y);
00763     if(SolveNormalEquations_){
00764       InvBlockDiagonal_->ApplyInverse(y,z);
00765       Apply_Transpose(Operator_,z, y);
00766     }
00767 
00768     IFPACK_CHK_ERR(y.Dot(x, &RQ_top));
00769     IFPACK_CHK_ERR(x.Dot(x, &RQ_bottom));
00770     lambda_max = RQ_top / RQ_bottom;
00771     IFPACK_CHK_ERR(y.Norm2(&norm));
00772     if (norm == 0.0) IFPACK_CHK_ERR(-1);
00773     IFPACK_CHK_ERR(x.Update(1.0 / norm, y, 0.0));
00774   }
00775 
00776   return(0);
00777 }
00778 #endif
00779 
00780 //==============================================================================
00781 #ifdef HAVE_IFPACK_EPETRAEXT
00782 int Ifpack_Polynomial::
00783 CG(const int MaximumIterations,
00784    double& lambda_min, double& lambda_max)
00785 {
00786   IFPACK_CHK_ERR(-1);// NTS: This always seems to yield errors in AztecOO, ergo,
00787                      // I turned it off.
00788 
00789   if(!UseBlockMode_) IFPACK_CHK_ERR(-1);
00790 
00791 #ifdef HAVE_IFPACK_AZTECOO
00792   Epetra_Vector x(Operator_->OperatorDomainMap());
00793   Epetra_Vector y(Operator_->OperatorRangeMap());
00794   x.Random();
00795   y.PutScalar(0.0);
00796   Epetra_LinearProblem LP(const_cast<Epetra_RowMatrix*>(&*Matrix_), &x, &y);
00797 
00798   AztecOO solver(LP);
00799   solver.SetAztecOption(AZ_solver, AZ_cg_condnum);
00800   solver.SetAztecOption(AZ_output, AZ_none);
00801 
00802   solver.SetPrecOperator(&*InvBlockDiagonal_);
00803   solver.Iterate(MaximumIterations, 1e-10);
00804 
00805   const double* status = solver.GetAztecStatus();
00806 
00807   lambda_min = status[AZ_lambda_min];
00808   lambda_max = status[AZ_lambda_max];
00809 
00810   return(0);
00811 #else
00812   cout << "You need to configure IFPACK with support for AztecOO" << endl;
00813   cout << "to use the CG estimator. This may require --enable-aztecoo" << endl;
00814   cout << "in your configure script." << endl;
00815   IFPACK_CHK_ERR(-1);
00816 #endif
00817 }
00818 #endif
00819 
00820 //==============================================================================
00821 int Ifpack_Polynomial::
00822 GMRES(const Epetra_Operator& Operator,
00823       const Epetra_Vector& InvPointDiagonal,
00824       const int MaximumIterations,
00825       double& lambda_real_min, double& lambda_real_max,
00826       double& lambda_imag_min, double& lambda_imag_max)
00827 {
00828 #ifdef HAVE_IFPACK_AZTECOO
00829   Epetra_Vector x(Operator_->OperatorDomainMap());
00830   Epetra_Vector y(Operator_->OperatorRangeMap());
00831   x.Random();
00832   y.PutScalar(0.0);
00833   Epetra_LinearProblem LP(const_cast<Epetra_RowMatrix*>(&*Matrix_), &x, &y);
00834   AztecOO solver(LP);
00835   solver.SetAztecOption(AZ_solver, AZ_gmres_condnum);
00836   solver.SetAztecOption(AZ_output, AZ_none);
00837   Ifpack_DiagPreconditioner diag(Operator.OperatorDomainMap(),
00838                                  Operator.OperatorRangeMap(),
00839                                  InvPointDiagonal);
00840   solver.SetPrecOperator(&diag);
00841   solver.Iterate(MaximumIterations, 1e-10);
00842   const double* status = solver.GetAztecStatus();
00843   lambda_real_min = status[AZ_lambda_real_min];
00844   lambda_real_max = status[AZ_lambda_real_max];
00845   lambda_imag_min = status[AZ_lambda_imag_min];
00846   lambda_imag_max = status[AZ_lambda_imag_max];
00847   return(0);
00848 #else
00849   cout << "You need to configure IFPACK with support for AztecOO" << endl;
00850   cout << "to use the GMRES estimator. This may require --enable-aztecoo" << endl;
00851   cout << "in your configure script." << endl;
00852   IFPACK_CHK_ERR(-1);
00853 #endif
00854 }
 All Classes Files Functions Variables Enumerations Friends