IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_SILU.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_SILU.h"
00045 #ifdef HAVE_IFPACK_SUPERLU
00046 
00047 #include "Ifpack_CondestType.h"
00048 #include "Epetra_ConfigDefs.h"
00049 #include "Epetra_Comm.h"
00050 #include "Epetra_Map.h"
00051 #include "Epetra_RowMatrix.h"
00052 #include "Epetra_Vector.h"
00053 #include "Epetra_MultiVector.h"
00054 #include "Epetra_CrsGraph.h"
00055 #include "Epetra_CrsMatrix.h"
00056 #include "Teuchos_ParameterList.hpp"
00057 #include "Teuchos_RefCountPtr.hpp"
00058 
00059 // SuperLU includes
00060 extern "C" {int dfill_diag(int n, NCformat *Astore);}
00061 
00062 using Teuchos::RefCountPtr;
00063 using Teuchos::rcp;
00064 
00065 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00066 #  include "Teuchos_TimeMonitor.hpp"
00067 #endif
00068 
00069 //==============================================================================
00070 Ifpack_SILU::Ifpack_SILU(Epetra_RowMatrix* Matrix_in) :
00071   A_(rcp(Matrix_in,false)),
00072   Comm_(Matrix_in->Comm()),
00073   UseTranspose_(false),
00074   NumMyDiagonals_(0),
00075   DropTol_(1e-4),
00076   FillTol_(1e-2),
00077   FillFactor_(10.0),
00078   DropRule_(9), 
00079   Condest_(-1.0),
00080   IsInitialized_(false),
00081   IsComputed_(false),
00082   NumInitialize_(0),
00083   NumCompute_(0),
00084   NumApplyInverse_(0),
00085   InitializeTime_(0.0),
00086   ComputeTime_(0.0),
00087   ApplyInverseTime_(0.0),
00088   Time_(Comm()),
00089   etree_(0),
00090   perm_r_(0),
00091   perm_c_(0)
00092 {
00093   Teuchos::ParameterList List;
00094   SetParameters(List);
00095   SY_.Store=0;
00096 }
00097 
00098 
00099 
00100 //==============================================================================
00101 void Ifpack_SILU::Destroy()
00102 {
00103   if(IsInitialized_){
00104     // SuperLU cleanup
00105     StatFree(&stat_);
00106 
00107     Destroy_CompCol_Permuted(&SAc_);
00108     Destroy_SuperNode_Matrix(&SL_);
00109     Destroy_CompCol_Matrix(&SU_);
00110 
00111     // Make sure NOT to clean up Epetra's memory
00112     Destroy_SuperMatrix_Store(&SA_);
00113     if(SY_.Store) Destroy_SuperMatrix_Store(&SY_);
00114     SY_.Store=0;
00115 
00116     // Cleanup stuff I allocated
00117     delete [] etree_;etree_=0;
00118     delete [] perm_r_;perm_r_=0;
00119     delete [] perm_c_;perm_c_=0;  
00120   }
00121 }
00122 
00123 //==========================================================================
00124 int Ifpack_SILU::SetParameters(Teuchos::ParameterList& List)
00125 {
00126   DropTol_=List.get("fact: drop tolerance",DropTol_);
00127   FillTol_=List.get("fact: zero pivot threshold",FillTol_);
00128   FillFactor_=List.get("fact: maximum fill factor",FillFactor_);
00129   DropRule_=List.get("fact: silu drop rule",DropRule_);
00130 
00131   // set label
00132   sprintf(Label_, "IFPACK SILU (drop=%d, zpv=%f, ffact=%f, rthr=%f)",
00133       DropRule(),FillTol(),FillFactor(),DropTol());
00134   return(0);
00135 }
00136 
00137 //==========================================================================
00138 template<typename int_type>
00139 int Ifpack_SILU::TInitialize() 
00140 {
00141 
00142 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00143   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_SILU::Initialize");
00144 #endif
00145 
00146   Time_.ResetStartTime();
00147 
00148   // reset this object
00149   Destroy();
00150 
00151   IsInitialized_ = false;
00152 
00153   Epetra_CrsMatrix* CrsMatrix;
00154   CrsMatrix = dynamic_cast<Epetra_CrsMatrix*>(&*A_);
00155 
00156   if(CrsMatrix && CrsMatrix->RowMap().SameAs(CrsMatrix->ColMap()) && CrsMatrix->IndicesAreContiguous()){
00157     // Case #1: Use original matrix
00158     Aover_=rcp(CrsMatrix,false);
00159   }
00160   else if(CrsMatrix && CrsMatrix->IndicesAreContiguous()){
00161     // Case #2: Extract using CrsDataPointers w/ contiguous indices
00162     int size = A_->MaxNumEntries();
00163     int N=A_->NumMyRows();
00164     Aover_ = rcp(new Epetra_CrsMatrix(Copy,A_->RowMatrixRowMap(), size));
00165     std::vector<int_type> Indices(size);
00166     std::vector<double> Values(size);
00167 
00168     int i,j,ct,*rowptr,*colind;
00169     double *values;
00170     IFPACK_CHK_ERR(CrsMatrix->ExtractCrsDataPointers(rowptr,colind,values));
00171 
00172     // Use the fact that EpetraCrsMatrices always number the off-processor columns *LAST*   
00173     for(i=0;i<N;i++){
00174       for(j=rowptr[i],ct=0;j<rowptr[i+1];j++){
00175     if(colind[j]<N){
00176       Indices[ct]= (int_type) CrsMatrix->GCID64(colind[j]);
00177       Values[ct]=values[j];
00178       ct++;
00179     }
00180       }
00181       Aover_->InsertGlobalValues((int_type) CrsMatrix->GRID64(i),ct,&Values[0],&Indices[0]);
00182     }
00183     IFPACK_CHK_ERR(Aover_->FillComplete(CrsMatrix->RowMap(),CrsMatrix->RowMap()));  
00184   }
00185   else{
00186     // Case #3: Extract using copys
00187     int size = A_->MaxNumEntries();
00188     Aover_ = rcp(new Epetra_CrsMatrix(Copy,A_->RowMatrixRowMap(), size));
00189     if (Aover_.get() == 0) IFPACK_CHK_ERR(-5); // memory allocation error
00190 
00191     std::vector<int> Indices1(size);
00192     std::vector<int_type> Indices2(size);
00193     std::vector<double> Values1(size),Values2(size);
00194 
00195     // extract each row at-a-time, and insert it into
00196     // the graph, ignore all off-process entries
00197     int N=A_->NumMyRows();
00198     for (int i = 0 ; i < N ; ++i) {
00199       int NumEntries;
00200       int_type GlobalRow = (int_type) A_->RowMatrixRowMap().GID64(i);
00201       IFPACK_CHK_ERR(A_->ExtractMyRowCopy(i, size, NumEntries, 
00202                       &Values1[0], &Indices1[0]));
00203 
00204       // convert to global indices, keeping only on-proc entries
00205       int ct=0;
00206       for (int j=0; j < NumEntries ; ++j) {
00207     if(Indices1[j] < N){
00208       Indices2[ct] = (int_type) A_->RowMatrixColMap().GID64(Indices1[j]);
00209       Values2[ct]=Values1[j];
00210       ct++;
00211     } 
00212       }
00213       IFPACK_CHK_ERR(Aover_->InsertGlobalValues(GlobalRow,ct,
00214                         &Values2[0],&Indices2[0]));
00215     }    
00216     IFPACK_CHK_ERR(Aover_->FillComplete(A_->RowMatrixRowMap(),A_->RowMatrixRowMap()));
00217   }
00218 
00219   // Finishing touches
00220   Aover_->OptimizeStorage();
00221   Graph_=rcp(const_cast<Epetra_CrsGraph*>(&Aover_->Graph()),false); 
00222 
00223   IsInitialized_ = true;
00224   NumInitialize_++;
00225   InitializeTime_ += Time_.ElapsedTime();
00226 
00227   return(0);
00228 }
00229 
00230 int Ifpack_SILU::Initialize() {
00231 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00232   if(A_->RowMatrixRowMap().GlobalIndicesInt()) {
00233     return TInitialize<int>();
00234   }
00235   else
00236 #endif
00237 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00238   if(A_->RowMatrixRowMap().GlobalIndicesLongLong()) {
00239     return TInitialize<long long>();
00240   }
00241   else
00242 #endif
00243     throw "Ifpack_SILU::Initialize: GlobalIndices type unknown for A_";
00244 }
00245 
00246 
00247 //==========================================================================
00248 int Ifpack_SILU::Compute() 
00249 {
00250 
00251 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00252   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_SILU::Compute");
00253 #endif
00254 
00255   if (!IsInitialized()) 
00256     IFPACK_CHK_ERR(Initialize());
00257 
00258   Time_.ResetStartTime();
00259   IsComputed_ = false;
00260 
00261   // Initialize the SuperLU statistics & options variables.
00262   StatInit(&stat_);
00263   ilu_set_default_options(&options_);
00264   options_.ILU_DropTol=DropTol_;
00265   options_.ILU_FillTol=FillTol_;
00266   options_.ILU_DropRule=DropRule_;
00267   options_.ILU_FillFactor=FillFactor_;
00268 
00269   // Grab pointers from Aover_
00270   int *rowptr,*colind;
00271   double *values;
00272   IFPACK_CHK_ERR(Aover_->ExtractCrsDataPointers(rowptr,colind,values));
00273   int N=Aover_->NumMyRows();
00274 
00275   // Copy the data over to SuperLU land - mark as a transposed CompCol Matrix
00276   dCreate_CompCol_Matrix(&SA_,N,N,Aover_->NumMyNonzeros(),
00277              values,colind,rowptr,SLU_NC,SLU_D,SLU_GE);
00278 
00279   // Fill any zeros on the diagonal
00280   // Commented out for now
00281   dfill_diag(N, (NCformat*)SA_.Store);
00282 
00283   // Allocate SLU memory
00284   etree_=new int [N];
00285   perm_r_=new int[N];
00286   perm_c_=new int[N];
00287 
00288   // Get column permutation
00289   int permc_spec=options_.ColPerm;
00290   if ( permc_spec != MY_PERMC && options_.Fact == DOFACT )
00291     get_perm_c(permc_spec,&SA_,perm_c_);
00292 
00293   // Preorder by column permutation
00294   sp_preorder(&options_, &SA_, perm_c_, etree_, &SAc_);
00295 
00296   // Call the factorization
00297   int panel_size = sp_ienv(1);
00298   int relax      = sp_ienv(2);
00299   int info=0;
00300   dgsitrf(&options_,&SAc_,relax,panel_size,etree_,NULL,0,perm_c_,perm_r_,&SL_,&SU_,&stat_,&info);
00301   if(info<0) IFPACK_CHK_ERR(info);
00302 
00303   IsComputed_ = true;
00304   NumCompute_++;
00305   ComputeTime_ += Time_.ElapsedTime();
00306   return 0;
00307 }
00308 
00309 //=============================================================================
00310 // This function finds Y such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00311 int Ifpack_SILU::Solve(bool Trans, const Epetra_MultiVector& X, 
00312                       Epetra_MultiVector& Y) const 
00313 {
00314 
00315 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00316   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_SILU::ApplyInverse - Solve");
00317 #endif
00318 
00319   if (!IsComputed())
00320     IFPACK_CHK_ERR(-3);
00321   int nrhs=X.NumVectors();
00322   int N=A_->NumMyRows();
00323 
00324   // Copy X over to Y
00325   Y=X;
00326 
00327   // Move to SuperLU land
00328   // NTS: Need to do epetra-style realloc-if-nrhs-changes thing
00329   if(SY_.Store) Destroy_SuperMatrix_Store(&SY_);
00330   SY_.Store=0;
00331   dCreate_Dense_Matrix(&SY_,N,nrhs,Y[0],N,SLU_DN,SLU_D,SLU_GE);
00332 
00333   int info;
00334   dgstrs(TRANS,&SL_,&SU_,perm_c_,perm_r_,&SY_,&stat_,&info);
00335   if(!info) IFPACK_CHK_ERR(info);
00336 
00337   return(info);
00338 }
00339 
00340 //=============================================================================
00341 // This function finds X such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00342 int Ifpack_SILU::Multiply(bool Trans, const Epetra_MultiVector& X, 
00343                 Epetra_MultiVector& Y) const 
00344 {
00345 
00346   if (!IsComputed())
00347     IFPACK_CHK_ERR(-1);
00348 
00349   return(0);
00350 }
00351 
00352 //=============================================================================
00353 // This function finds X such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00354 int Ifpack_SILU::ApplyInverse(const Epetra_MultiVector& X, 
00355                              Epetra_MultiVector& Y) const
00356 {
00357 
00358 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00359   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_SILU::ApplyInverse");
00360 #endif
00361 
00362   if (!IsComputed())
00363     IFPACK_CHK_ERR(-3);
00364 
00365   if (X.NumVectors() != Y.NumVectors())
00366     IFPACK_CHK_ERR(-2);
00367 
00368   Time_.ResetStartTime();
00369 
00370   // AztecOO gives X and Y pointing to the same memory location,
00371   // need to create an auxiliary vector, Xcopy
00372   Teuchos::RefCountPtr< const Epetra_MultiVector > Xcopy;
00373   if (X.Pointers()[0] == Y.Pointers()[0])
00374     Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) );
00375   else
00376     Xcopy = Teuchos::rcp( &X, false );
00377 
00378   IFPACK_CHK_ERR(Solve(Ifpack_SILU::UseTranspose(), *Xcopy, Y));
00379 
00380   ++NumApplyInverse_;
00381   ApplyInverseTime_ += Time_.ElapsedTime();
00382 
00383   return(0);
00384 
00385 }
00386 
00387 //=============================================================================
00388 double Ifpack_SILU::Condest(const Ifpack_CondestType CT, 
00389                            const int MaxIters, const double Tol,
00390                               Epetra_RowMatrix* Matrix_in)
00391 {
00392 
00393 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00394   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_SILU::Condest");
00395 #endif
00396 
00397   if (!IsComputed()) // cannot compute right now
00398     return(-1.0);
00399 
00400   Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00401 
00402   return(Condest_);
00403 }
00404 
00405 //=============================================================================
00406 std::ostream&
00407 Ifpack_SILU::Print(std::ostream& os) const
00408 {
00409   if (!Comm().MyPID()) {
00410     os << endl;
00411     os << "================================================================================" << endl;
00412     os << "Ifpack_SILU: " << Label() << endl << endl;
00413     os << "Dropping rule      = "<< DropRule() << endl;
00414     os << "Zero pivot thresh  = "<< FillTol() << endl;
00415     os << "Max fill factor    = "<< FillFactor() << endl;
00416     os << "Drop tolerance     = "<< DropTol() << endl;
00417     os << "Condition number estimate = " << Condest() << endl;
00418     os << "Global number of rows     = " << A_->NumGlobalRows64() << endl;
00419     if (IsComputed_) {
00420       // Internal SuperLU info
00421       int fnnz=0;
00422       if(SL_.Store) fnnz+=((SCformat*)SL_.Store)->nnz;
00423       if(SU_.Store) fnnz+=((NCformat*)SU_.Store)->nnz;
00424       int lufill=fnnz - A_->NumMyRows();
00425       os << "No. of nonzeros in L+U    = "<< lufill<<endl;
00426       os << "Fill ratio: nnz(F)/nnz(A) = "<<(double)lufill / (double)A_->NumMyNonzeros()<<endl;
00427     }
00428     os << endl;
00429     os << "Phase           # calls   Total Time (s)       Total MFlops     MFlops/s" << endl;
00430     os << "-----           -------   --------------       ------------     --------" << endl;
00431     os << "Initialize()    "   << std::setw(5) << NumInitialize() 
00432        << "  " << std::setw(15) << InitializeTime() 
00433        << "              0.0              0.0" << endl;
00434     os << "Compute()       "   << std::setw(5) << NumCompute() 
00435        << "  " << std::setw(15) << ComputeTime()
00436        << "  " << std::setw(15) << 1.0e-6 * ComputeFlops();
00437     if (ComputeTime() != 0.0) 
00438       os << "  " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
00439     else
00440       os << "  " << std::setw(15) << 0.0 << endl;
00441     os << "ApplyInverse()  "   << std::setw(5) << NumApplyInverse() 
00442        << "  " << std::setw(15) << ApplyInverseTime()
00443        << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
00444     if (ApplyInverseTime() != 0.0) 
00445       os << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
00446     else
00447       os << "  " << std::setw(15) << 0.0 << endl;
00448     os << "================================================================================" << endl;
00449     os << endl;
00450   }
00451 
00452   return(os);
00453 }
00454 
00455 #endif
 All Classes Files Functions Variables Enumerations Friends