IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_IKLU.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 "Ifpack_Preconditioner.h"
00045 #include "Ifpack_IKLU.h"
00046 #include "Ifpack_Condest.h"
00047 #include "Ifpack_Utils.h"
00048 #include "Ifpack_HashTable.h"
00049 #include "Epetra_SerialComm.h"
00050 #include "Epetra_Comm.h"
00051 #include "Epetra_Map.h"
00052 #include "Epetra_RowMatrix.h"
00053 #include "Epetra_CrsMatrix.h"
00054 #include "Epetra_Vector.h"
00055 #include "Epetra_MultiVector.h"
00056 #include "Epetra_Util.h"
00057 #include "Teuchos_ParameterList.hpp"
00058 #include "Teuchos_RefCountPtr.hpp"
00059 #include <functional>
00060 #include <algorithm>
00061 
00062 using namespace Teuchos;
00063 
00064 //==============================================================================
00065 // FIXME: allocate Comm_ and Time_ the first Initialize() call
00066 Ifpack_IKLU::Ifpack_IKLU(const Epetra_RowMatrix* A) :
00067   A_(*A),
00068   Comm_(A->Comm()),
00069   Condest_(-1.0),
00070   Relax_(0.),
00071   Athresh_(0.0),
00072   Rthresh_(1.0),
00073   LevelOfFill_(1.0),
00074   DropTolerance_(1e-12),
00075   IsInitialized_(false),
00076   IsComputed_(false),
00077   UseTranspose_(false),
00078   NumMyRows_(-1),
00079   NumInitialize_(0),
00080   NumCompute_(0),
00081   NumApplyInverse_(0),
00082   InitializeTime_(0.0),
00083   ComputeTime_(0.0),
00084   ApplyInverseTime_(0.0),
00085   ComputeFlops_(0.0),
00086   ApplyInverseFlops_(0.0),
00087   Time_(Comm()),
00088   GlobalNonzeros_(0),
00089   csrA_(0),
00090   cssS_(0),
00091   csrnN_(0)
00092 {
00093   // do nothing here..
00094 }
00095 
00096 //==============================================================================
00097 Ifpack_IKLU::~Ifpack_IKLU()
00098 {
00099   Destroy();
00100 }
00101 
00102 //==============================================================================
00103 void Ifpack_IKLU::Destroy()
00104 {
00105   IsInitialized_ = false;
00106   IsComputed_ = false;
00107   if (csrA_)
00108     csr_spfree( csrA_ );
00109   if (cssS_)
00110     csr_sfree( cssS_ );
00111   if (csrnN_)
00112     csr_nfree( csrnN_ );
00113 }
00114 
00115 //==========================================================================
00116 int Ifpack_IKLU::SetParameters(Teuchos::ParameterList& List)
00117 {
00118   try 
00119   {
00120     LevelOfFill_ = List.get<double>("fact: ilut level-of-fill", LevelOfFill());
00121     if (LevelOfFill_ <= 0.0)
00122       IFPACK_CHK_ERR(-2); // must be greater than 0.0
00123 
00124     Athresh_ = List.get<double>("fact: absolute threshold", Athresh_);
00125     Rthresh_ = List.get<double>("fact: relative threshold", Rthresh_);
00126     Relax_ = List.get<double>("fact: relax value", Relax_);
00127     DropTolerance_ = List.get<double>("fact: drop tolerance", DropTolerance_);
00128 
00129     Label_ = "IFPACK IKLU (fill=" + Ifpack_toString(LevelOfFill())
00130       + ", relax=" + Ifpack_toString(RelaxValue())
00131       + ", athr=" + Ifpack_toString(AbsoluteThreshold())
00132       + ", rthr=" + Ifpack_toString(RelativeThreshold())
00133       + ", droptol=" + Ifpack_toString(DropTolerance())
00134       + ")";
00135     return(0);
00136   }
00137   catch (...)
00138   {
00139     cerr << "Caught an exception while parsing the parameter list" << endl;
00140     cerr << "This typically means that a parameter was set with the" << endl;
00141     cerr << "wrong type (for example, int instead of double). " << endl;
00142     cerr << "please check the documentation for the type required by each parameer." << endl;
00143     IFPACK_CHK_ERR(-1);
00144   }
00145 
00146   return(0);
00147 }
00148 
00149 //==========================================================================
00150 int Ifpack_IKLU::Initialize()
00151 {
00152   // delete previously allocated factorization
00153   Destroy();
00154 
00155   Time_.ResetStartTime();
00156 
00157   if (A_.Comm().NumProc() != 1) {
00158     cout << " There are too many processors !!! " << endl;
00159     cerr << "Ifpack_IKLU can be used with Comm().NumProc() == 1" << endl;
00160     cerr << "only. This class is a subdomain solver for Ifpack_AdditiveSchwarz," << endl;
00161     cerr << "and it is currently not meant to be used otherwise." << endl;
00162     exit(EXIT_FAILURE);
00163   }
00164   
00165   // check dimensions of input matrix only in serial
00166   if (Comm().NumProc() == 1 && Matrix().NumMyRows() != Matrix().NumMyCols())
00167     IFPACK_CHK_ERR(-2);
00168     
00169   NumMyRows_ = Matrix().NumMyRows();
00170   NumMyNonzeros_ = Matrix().NumMyNonzeros();
00171 
00172   int RowNnz, Length = Matrix().MaxNumEntries();
00173   std::vector<int>    RowIndices(Length);
00174   std::vector<double> RowValues(Length);
00175 
00176   //cout << "Processor " << Comm().MyPID() << " owns " << NumMyRows_ << " rows and has " << NumMyNonzeros_ << " nonzeros " << endl;
00177   // get general symbolic structure of the matrix
00178   csrA_ = csr_spalloc( NumMyRows_, NumMyRows_, NumMyNonzeros_, 1, 0 );
00179 
00180   // copy the symbolic structure into csrA_
00181   int count = 0;
00182   csrA_->p[0] = 0;
00183   for (int i = 0; i < NumMyRows_; ++i ) {
00184 
00185     IFPACK_CHK_ERR(A_.ExtractMyRowCopy(i,Length,RowNnz,
00186                        &RowValues[0],&RowIndices[0]));
00187     for (int j = 0 ; j < RowNnz ; ++j) {
00188       csrA_->j[count++] = RowIndices[j];
00189       //cout << "Row = " << i << ", Column = " << RowIndices[j] << ", Value = " << RowValues[j] << endl;
00190     }
00191     csrA_->p[i+1] = csrA_->p[i] + RowNnz;
00192   }
00193 
00194   // Perform symbolic analysis on the current matrix structure
00195   int order = 1;
00196   cssS_ = csr_sqr( order, csrA_ );
00197   for (int i = 0; i < NumMyRows_; ++i ) {
00198      cout << "AMD Perm (from inside KLU) [" << i << "] = " << cssS_->q[i] << endl;
00199   }
00200 
00201   // nothing else to do here
00202   IsInitialized_ = true;
00203   ++NumInitialize_;
00204   InitializeTime_ += Time_.ElapsedTime();
00205 
00206   return(0);
00207 }
00208 
00209 //==========================================================================
00210 class Ifpack_AbsComp 
00211 {
00212  public:
00213   inline bool operator()(const double& x, const double& y) 
00214   {
00215     return(IFPACK_ABS(x) > IFPACK_ABS(y));
00216   }
00217 };
00218 
00219 //==========================================================================
00220 
00221 int Ifpack_IKLU::Compute() 
00222 {
00223   if (!IsInitialized()) 
00224     IFPACK_CHK_ERR(Initialize());
00225 
00226   Time_.ResetStartTime();
00227   IsComputed_ = false;
00228 
00229   NumMyRows_ = A_.NumMyRows();
00230   int Length = A_.MaxNumEntries();
00231 
00232   bool distributed = (Comm().NumProc() > 1)?true:false;
00233 #if !defined(EPETRA_NO_32BIT_GLOBAL_INDICES) || !defined(EPETRA_NO_64BIT_GLOBAL_INDICES)
00234   if (distributed)
00235   {
00236     SerialComm_ = rcp(new Epetra_SerialComm);
00237     SerialMap_ = rcp(new Epetra_Map(NumMyRows_, 0, *SerialComm_));
00238     assert (SerialComm_.get() != 0);
00239     assert (SerialMap_.get() != 0);
00240   }
00241   else
00242     SerialMap_ = rcp(const_cast<Epetra_Map*>(&A_.RowMatrixRowMap()), false);
00243 #endif
00244 
00245   int RowNnz;
00246   std::vector<int>    RowIndices(Length);
00247   std::vector<double> RowValues(Length);
00248 
00249   // copy the values from A_ into csrA_
00250   int count = 0;
00251   for (int i = 0; i < NumMyRows_; ++i ) {
00252 
00253     IFPACK_CHK_ERR(A_.ExtractMyRowCopy(i,Length,RowNnz,
00254                        &RowValues[0],&RowIndices[0]));
00255     // make sure each row has the same number of nonzeros
00256     if (RowNnz != (csrA_->p[i+1]-csrA_->p[i])) {
00257       cout << "The number of nonzeros for this row does not math the expected number of nonzeros!!!" << endl;
00258     }
00259     for (int j = 0 ; j < RowNnz ; ++j) {
00260       
00261       csrA_->x[count++] = RowValues[j];
00262       //cout << "Row = " << i << ", Column = " << RowIndices[j] << ", Value = " << RowValues[j] << endl;
00263     }
00264   }
00265   
00266   // compute the lu factors
00267   double tol = 0.1;
00268   csrnN_ = csr_lu( &*csrA_, &*cssS_, tol );
00269 
00270   // Create L and U as a view of the information stored in csrnN_->L and csrnN_->U
00271   csr* L_tmp = csrnN_->L;
00272   csr* U_tmp = csrnN_->U;
00273   std::vector<int> numEntriesL( NumMyRows_ ), numEntriesU( NumMyRows_ );
00274   for (int i=0; i < NumMyRows_; ++i) {
00275     numEntriesL[i] = ( L_tmp->p[i+1] - L_tmp->p[i] );
00276     numEntriesU[i] = ( U_tmp->p[i+1] - U_tmp->p[i] );
00277   }
00278   L_ = rcp(new Epetra_CrsMatrix(View, *SerialMap_, &numEntriesL[0]));
00279   U_ = rcp(new Epetra_CrsMatrix(View, *SerialMap_, &numEntriesU[0]));
00280 
00281   // Insert the values into L and U
00282 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00283     if(SerialMap_->GlobalIndicesInt()) {
00284       for (int i=0; i < NumMyRows_; ++i) {
00285         L_->InsertGlobalValues( i, numEntriesL[i], &(L_tmp->x[L_tmp->p[i]]), &(L_tmp->j[L_tmp->p[i]]) );
00286         U_->InsertGlobalValues( i, numEntriesU[i], &(U_tmp->x[U_tmp->p[i]]), &(U_tmp->j[U_tmp->p[i]]) );
00287       }
00288     }
00289     else
00290 #endif
00291 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00292     if(SerialMap_->GlobalIndicesLongLong()) {
00293 
00294       const int MaxNumEntries_L_U = std::max(L_->MaxNumEntries(), U_->MaxNumEntries());
00295       std::vector<long long> entries(MaxNumEntries_L_U);
00296 
00297       for (int i=0; i < NumMyRows_; ++i) {
00298         std::copy(&(L_tmp->j[L_tmp->p[i]]), &(L_tmp->j[L_tmp->p[i]]) + numEntriesL[i], entries.begin());
00299         L_->InsertGlobalValues( i, numEntriesL[i], &(L_tmp->x[L_tmp->p[i]]), &(entries[0]) );
00300 
00301         std::copy(&(U_tmp->j[U_tmp->p[i]]), &(U_tmp->j[U_tmp->p[i]]) + numEntriesU[i], entries.begin());
00302         U_->InsertGlobalValues( i, numEntriesU[i], &(U_tmp->x[U_tmp->p[i]]), &(entries[0]) );
00303       }
00304     }
00305     else
00306 #endif
00307       throw "Ifpack_IKLU::Compute: GlobalIndices type unknown for SerialMap_";
00308 
00309   IFPACK_CHK_ERR(L_->FillComplete());
00310   IFPACK_CHK_ERR(U_->FillComplete());
00311 
00312   long long MyNonzeros = L_->NumGlobalNonzeros64() + U_->NumGlobalNonzeros64();
00313   Comm().SumAll(&MyNonzeros, &GlobalNonzeros_, 1);
00314 
00315   IsComputed_ = true;
00316 
00317   ++NumCompute_;
00318   ComputeTime_ += Time_.ElapsedTime();
00319 
00320   return(0);
00321 
00322 }
00323   
00324 //=============================================================================
00325 int Ifpack_IKLU::ApplyInverse(const Epetra_MultiVector& X, 
00326                  Epetra_MultiVector& Y) const
00327 {
00328   if (!IsComputed())
00329     IFPACK_CHK_ERR(-2); // compute preconditioner first
00330 
00331   if (X.NumVectors() != Y.NumVectors()) 
00332     IFPACK_CHK_ERR(-3); // Return error: X and Y not the same size
00333 
00334   Time_.ResetStartTime();
00335 
00336   // NOTE: L_ and U_ are based on SerialMap_, while Xcopy is based
00337   // on A.Map()... which are in general different. However, Solve()
00338   // does not seem to care... which is fine with me.
00339   //
00340   // AztecOO gives X and Y pointing to the same memory location,
00341   // need to create an auxiliary vector, Xcopy and apply permutation.
00342   std::vector<int> invq( NumMyRows_ );
00343 
00344   for (int i=0; i<NumMyRows_; ++i ) {
00345     csrnN_->perm[ csrnN_->pinv[i] ] = i;
00346     invq[ cssS_->q[i] ] = i;
00347   }
00348 
00349   Teuchos::RefCountPtr<Epetra_MultiVector> Xcopy = Teuchos::rcp( new Epetra_MultiVector(X.Map(),X.NumVectors()), false );
00350   Teuchos::RefCountPtr<Epetra_MultiVector> Ytemp = Teuchos::rcp( new Epetra_MultiVector(Y.Map(),Y.NumVectors()) );
00351 
00352   for (int i=0; i<NumMyRows_; ++i) {
00353     for (int j=0; j<X.NumVectors(); ++j) {
00354       Xcopy->ReplaceMyValue( invq[i], j, (*X(j))[i] );
00355     }
00356   }
00357 
00358   if (!UseTranspose_)
00359   {
00360     // solves LU Y = X 
00361     IFPACK_CHK_ERR(L_->Solve(false,false,false,*Xcopy,*Ytemp));
00362     IFPACK_CHK_ERR(U_->Solve(true,false,false,*Ytemp,*Ytemp));
00363   }
00364   else
00365   {
00366     // solves U(trans) L(trans) Y = X
00367     IFPACK_CHK_ERR(U_->Solve(true,true,false,*Xcopy,*Ytemp));
00368     IFPACK_CHK_ERR(L_->Solve(false,true,false,*Ytemp,*Ytemp));
00369   }
00370 
00371   // Reverse the permutation.
00372   for (int i=0; i<NumMyRows_; ++i) {
00373     for (int j=0; j<Y.NumVectors(); ++j) {
00374       Y.ReplaceMyValue( csrnN_->perm[i], j, (*(*Ytemp)(j))[i] );
00375     }
00376   }
00377 
00378   ++NumApplyInverse_;
00379 #ifdef IFPACK_FLOPCOUNTERS
00380   ApplyInverseFlops_ += X.NumVectors() * 2 * GlobalNonzeros_;
00381 #endif
00382   ApplyInverseTime_ += Time_.ElapsedTime();
00383 
00384   return(0);
00385 
00386 }
00387 //=============================================================================
00388 // This function finds X such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00389 int Ifpack_IKLU::Apply(const Epetra_MultiVector& X, 
00390               Epetra_MultiVector& Y) const 
00391 {
00392 
00393   return(-98);
00394 }
00395 
00396 //=============================================================================
00397 double Ifpack_IKLU::Condest(const Ifpack_CondestType CT, 
00398                             const int MaxIters, const double Tol,
00399                 Epetra_RowMatrix* Matrix_in)
00400 {
00401   if (!IsComputed()) // cannot compute right now
00402     return(-1.0);
00403 
00404   // NOTE: this is computing the *local* condest
00405   if (Condest_ == -1.0)
00406     Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00407 
00408   return(Condest_);
00409 }
00410 
00411 //=============================================================================
00412 std::ostream&
00413 Ifpack_IKLU::Print(std::ostream& os) const
00414 {
00415   if (!Comm().MyPID()) {
00416     os << endl;
00417     os << "================================================================================" << endl;
00418     os << "Ifpack_IKLU: " << Label() << endl << endl;
00419     os << "Level-of-fill      = " << LevelOfFill() << endl;
00420     os << "Absolute threshold = " << AbsoluteThreshold() << endl;
00421     os << "Relative threshold = " << RelativeThreshold() << endl;
00422     os << "Relax value        = " << RelaxValue() << endl;
00423     os << "Condition number estimate       = " << Condest() << endl;
00424     os << "Global number of rows           = " << A_.NumGlobalRows64() << endl;
00425     if (IsComputed_) {
00426       os << "Number of nonzeros in A         = " << A_.NumGlobalNonzeros64() << endl;
00427       os << "Number of nonzeros in L + U     = " << NumGlobalNonzeros64() 
00428          << " ( = " << 100.0 * NumGlobalNonzeros64() / A_.NumGlobalNonzeros64() 
00429          << " % of A)" << endl;
00430       os << "nonzeros / rows                 = " 
00431         << 1.0 * NumGlobalNonzeros64() / U_->NumGlobalRows64() << endl;
00432     }
00433     os << endl;
00434     os << "Phase           # calls   Total Time (s)       Total MFlops     MFlops/s" << endl;
00435     os << "-----           -------   --------------       ------------     --------" << endl;
00436     os << "Initialize()    "   << std::setw(5) << NumInitialize() 
00437        << "  " << std::setw(15) << InitializeTime() 
00438        << "               0.0            0.0" << endl;
00439     os << "Compute()       "   << std::setw(5) << NumCompute() 
00440        << "  " << std::setw(15) << ComputeTime()
00441        << "  " << std::setw(15) << 1.0e-6 * ComputeFlops(); 
00442     if (ComputeTime() != 0.0)
00443       os << "  " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
00444     else
00445       os << "  " << std::setw(15) << 0.0 << endl;
00446     os << "ApplyInverse()  "   << std::setw(5) << NumApplyInverse() 
00447        << "  " << std::setw(15) << ApplyInverseTime()
00448        << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
00449     if (ApplyInverseTime() != 0.0) 
00450       os << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
00451     else
00452       os << "  " << std::setw(15) << 0.0 << endl;
00453     os << "================================================================================" << endl;
00454     os << endl;
00455   }
00456 
00457   return(os);
00458 }
 All Classes Files Functions Variables Enumerations Friends