IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_ILU.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_CondestType.h"
00045 #include "Ifpack_ILU.h"
00046 #include "Epetra_ConfigDefs.h"
00047 #include "Epetra_Comm.h"
00048 #include "Epetra_Map.h"
00049 #include "Epetra_RowMatrix.h"
00050 #include "Epetra_Vector.h"
00051 #include "Epetra_MultiVector.h"
00052 #include "Epetra_CrsGraph.h"
00053 #include "Epetra_CrsMatrix.h"
00054 #include "Teuchos_ParameterList.hpp"
00055 #include "Teuchos_RefCountPtr.hpp"
00056 
00057 using Teuchos::RefCountPtr;
00058 using Teuchos::rcp;
00059 
00060 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00061 #  include "Teuchos_TimeMonitor.hpp"
00062 #endif
00063 
00064 //==============================================================================
00065 Ifpack_ILU::Ifpack_ILU(Epetra_RowMatrix* Matrix_in) :
00066   A_(rcp(Matrix_in,false)),
00067   Comm_(Matrix_in->Comm()),
00068   UseTranspose_(false),
00069   NumMyDiagonals_(0),
00070   RelaxValue_(0.0),
00071   Athresh_(0.0),
00072   Rthresh_(1.0),
00073   Condest_(-1.0),
00074   LevelOfFill_(0),
00075   IsInitialized_(false),
00076   IsComputed_(false),
00077   NumInitialize_(0),
00078   NumCompute_(0),
00079   NumApplyInverse_(0),
00080   InitializeTime_(0.0),
00081   ComputeTime_(0.0),
00082   ApplyInverseTime_(0.0),
00083   ComputeFlops_(0.0),
00084   ApplyInverseFlops_(0.0),
00085   Time_(Comm())
00086 {
00087   Teuchos::ParameterList List;
00088   SetParameters(List);
00089 }
00090 
00091 //==============================================================================
00092 void Ifpack_ILU::Destroy()
00093 {
00094   // reset pointers to already allocated stuff
00095   U_DomainMap_ = 0;
00096   L_RangeMap_ = 0;
00097 }
00098 
00099 //==========================================================================
00100 int Ifpack_ILU::SetParameters(Teuchos::ParameterList& List)
00101 {
00102   RelaxValue_ = List.get("fact: relax value", RelaxValue_);
00103   Athresh_ = List.get("fact: absolute threshold", Athresh_);
00104   Rthresh_ = List.get("fact: relative threshold", Rthresh_);
00105   LevelOfFill_ = List.get("fact: level-of-fill", LevelOfFill_);
00106 
00107   // set label
00108   sprintf(Label_, "IFPACK ILU (fill=%d, relax=%f, athr=%f, rthr=%f)",
00109       LevelOfFill(), RelaxValue(), AbsoluteThreshold(), 
00110       RelativeThreshold());
00111   return(0);
00112 }
00113 
00114 //==========================================================================
00115 int Ifpack_ILU::ComputeSetup() 
00116 {
00117 
00118 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00119   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::ComputeSetup");
00120 #endif
00121 
00122   L_ = rcp(new Epetra_CrsMatrix(Copy, Graph().L_Graph()));
00123   U_ = rcp(new Epetra_CrsMatrix(Copy, Graph().U_Graph()));
00124   D_ = rcp(new Epetra_Vector(Graph().L_Graph().RowMap()));
00125   if ((L_.get() == 0) || (U_.get() == 0) || (D_.get() == 0))
00126     IFPACK_CHK_ERR(-5);
00127 
00128   // Get Maximun Row length
00129   int MaxNumEntries = Matrix().MaxNumEntries();
00130 
00131   // Set L range map and U domain map
00132   U_DomainMap_ = &(Matrix().OperatorDomainMap());
00133   L_RangeMap_ = &(Matrix().OperatorRangeMap());
00134  
00135   // this is the old InitAllValues()
00136   int ierr = 0;
00137   int i, j;
00138   int NumIn, NumL, NumU;
00139   bool DiagFound;
00140   int NumNonzeroDiags = 0;
00141 
00142   std::vector<int> InI(MaxNumEntries); // Allocate temp space
00143   std::vector<int> LI(MaxNumEntries);
00144   std::vector<int> UI(MaxNumEntries);
00145   std::vector<double> InV(MaxNumEntries);
00146   std::vector<double> LV(MaxNumEntries);
00147   std::vector<double> UV(MaxNumEntries);
00148 
00149   bool ReplaceValues = (L_->StaticGraph() || L_->IndicesAreLocal()); // Check if values should be inserted or replaced
00150 
00151   if (ReplaceValues) {
00152     L_->PutScalar(0.0); // Zero out L and U matrices
00153     U_->PutScalar(0.0);
00154   }
00155 
00156   D_->PutScalar(0.0); // Set diagonal values to zero
00157   double *DV;
00158   IFPACK_CHK_ERR(D_->ExtractView(&DV)); // Get view of diagonal
00159 
00160   // First we copy the user's matrix into L and U, regardless of fill level
00161 
00162   for (i=0; i< NumMyRows(); i++) {
00163 
00164     IFPACK_CHK_ERR(Matrix().ExtractMyRowCopy(i, MaxNumEntries, NumIn, &InV[0], &InI[0])); // Get Values and Indices
00165     
00166     // Split into L and U (we don't assume that indices are ordered).
00167     
00168     NumL = 0; 
00169     NumU = 0; 
00170     DiagFound = false;
00171     
00172     for (j=0; j< NumIn; j++) {
00173       int k = InI[j];
00174 
00175       if (k==i) {
00176     DiagFound = true;
00177     DV[i] += Rthresh_ * InV[j] + EPETRA_SGN(InV[j]) * Athresh_; // Store perturbed diagonal in Epetra_Vector D_
00178       }
00179 
00180       else if (k < 0) {IFPACK_CHK_ERR(-4);} // Out of range
00181 
00182       else if (k < i) {
00183     LI[NumL] = k;
00184     LV[NumL] = InV[j];
00185     NumL++;
00186       }
00187       else if (k<NumMyRows()) {
00188     UI[NumU] = k;
00189     UV[NumU] = InV[j];
00190     NumU++;
00191       }
00192     }
00193     
00194     // Check in things for this row of L and U
00195 
00196     if (DiagFound) NumNonzeroDiags++;
00197     else DV[i] = Athresh_;
00198 
00199     if (NumL) {
00200       if (ReplaceValues) {
00201     (L_->ReplaceMyValues(i, NumL, &LV[0], &LI[0]));
00202       }
00203       else {
00204     IFPACK_CHK_ERR(L_->InsertMyValues(i, NumL, &LV[0], &LI[0]));
00205       }
00206     }
00207 
00208     if (NumU) {
00209       if (ReplaceValues) {
00210     (U_->ReplaceMyValues(i, NumU, &UV[0], &UI[0]));
00211       }
00212       else {
00213     IFPACK_CHK_ERR(U_->InsertMyValues(i, NumU, &UV[0], &UI[0]));
00214       }
00215     }
00216     
00217   }
00218 
00219   if (!ReplaceValues) {
00220     // The domain of L and the range of U are exactly their own row maps (there is no communication).
00221     // The domain of U and the range of L must be the same as those of the original matrix,
00222     // However if the original matrix is a VbrMatrix, these two latter maps are translation from
00223     // a block map to a point map.
00224     IFPACK_CHK_ERR(L_->FillComplete((L_->RowMatrixColMap()), *L_RangeMap_));
00225     IFPACK_CHK_ERR(U_->FillComplete(*U_DomainMap_, U_->RowMatrixRowMap()));
00226   }
00227 
00228   // At this point L and U have the values of A in the structure of L and U, and diagonal vector D
00229   int TotalNonzeroDiags = 0;
00230   IFPACK_CHK_ERR(Graph().L_Graph().RowMap().Comm().SumAll(&NumNonzeroDiags, &TotalNonzeroDiags, 1));
00231   NumMyDiagonals_ = NumNonzeroDiags;
00232   if (NumNonzeroDiags != NumMyRows()) ierr = 1; // Diagonals are not right, warn user
00233 
00234   IFPACK_CHK_ERR(ierr);
00235   return(ierr);
00236 }
00237 
00238 //==========================================================================
00239 int Ifpack_ILU::Initialize() 
00240 {
00241 
00242 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00243   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::Initialize");
00244 #endif
00245 
00246   Time_.ResetStartTime();
00247   IsInitialized_ = false;
00248 
00249   // reset this object
00250   Destroy();
00251 
00252   Epetra_CrsMatrix* CrsMatrix;
00253   CrsMatrix = dynamic_cast<Epetra_CrsMatrix*>(&*A_);
00254   if (CrsMatrix == 0) {
00255     // this means that we have to create
00256     // the graph from a given Epetra_RowMatrix. Note
00257     // that at this point we are ignoring any possible
00258     // graph coming from VBR matrices.
00259     int size = A_->MaxNumEntries();
00260     CrsGraph_ = rcp(new Epetra_CrsGraph(Copy,A_->RowMatrixRowMap(), size));
00261     if (CrsGraph_.get() == 0)
00262       IFPACK_CHK_ERR(-5); // memory allocation error
00263 
00264     std::vector<double> Values(size);
00265 
00266 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00267     if(A_->RowMatrixRowMap().GlobalIndicesInt()) {
00268       std::vector<int> Indices(size);
00269       // extract each row at-a-time, and insert it into
00270       // the graph, ignore all off-process entries
00271       for (int i = 0 ; i < A_->NumMyRows() ; ++i) {
00272         int NumEntries;
00273         int GlobalRow = A_->RowMatrixRowMap().GID(i);
00274         IFPACK_CHK_ERR(A_->ExtractMyRowCopy(i, size, NumEntries, 
00275                       &Values[0], &Indices[0]));
00276         // convert to global indices
00277         for (int j = 0 ; j < NumEntries ; ++j) {
00278           Indices[j] = A_->RowMatrixColMap().GID(Indices[j]); 
00279         }
00280         IFPACK_CHK_ERR(CrsGraph_->InsertGlobalIndices(GlobalRow,NumEntries,
00281                            &Indices[0]));
00282       }
00283     }
00284     else
00285 #endif
00286 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00287     if(A_->RowMatrixRowMap().GlobalIndicesLongLong()) {
00288       std::vector<int> Indices_local(size);
00289       std::vector<long long> Indices(size);
00290       // extract each row at-a-time, and insert it into
00291       // the graph, ignore all off-process entries
00292       for (int i = 0 ; i < A_->NumMyRows() ; ++i) {
00293         int NumEntries;
00294         long long GlobalRow = A_->RowMatrixRowMap().GID64(i);
00295         IFPACK_CHK_ERR(A_->ExtractMyRowCopy(i, size, NumEntries, 
00296                       &Values[0], &Indices_local[0]));
00297         // convert to global indices
00298         for (int j = 0 ; j < NumEntries ; ++j) {
00299           Indices[j] = A_->RowMatrixColMap().GID64(Indices_local[j]); 
00300         }
00301         IFPACK_CHK_ERR(CrsGraph_->InsertGlobalIndices(GlobalRow,NumEntries,
00302                            &Indices[0]));
00303       }
00304     }
00305     else
00306 #endif
00307       throw "Ifpack_ILU::Initialize: GlobalIndices type unknown";
00308 
00309     IFPACK_CHK_ERR(CrsGraph_->FillComplete(A_->RowMatrixRowMap(),
00310                       A_->RowMatrixRowMap()));
00311 
00312     // always overlap zero, wider overlap will be handled
00313     // by the AdditiveSchwarz preconditioner.
00314     Graph_ = rcp(new Ifpack_IlukGraph(*CrsGraph_, LevelOfFill_, 0));
00315 
00316   }
00317   else {
00318     // see comment above for the overlap.
00319     Graph_ = rcp(new Ifpack_IlukGraph(CrsMatrix->Graph(), LevelOfFill_, 0));
00320   }
00321 
00322   if (Graph_.get() == 0)
00323     IFPACK_CHK_ERR(-5); // memory allocation error
00324   IFPACK_CHK_ERR(Graph_->ConstructFilledGraph());
00325 
00326   IsInitialized_ = true;
00327   NumInitialize_++;
00328   InitializeTime_ += Time_.ElapsedTime();
00329 
00330   return(0);
00331 }
00332 
00333 //==========================================================================
00334 int Ifpack_ILU::Compute() 
00335 {
00336 
00337 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00338   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::Compute");
00339 #endif
00340 
00341   if (!IsInitialized()) 
00342     IFPACK_CHK_ERR(Initialize());
00343 
00344   Time_.ResetStartTime();
00345   IsComputed_ = false;
00346 
00347   // convert Matrix() into L and U factors.
00348   IFPACK_CHK_ERR(ComputeSetup());
00349 
00350   // MinMachNum should be officially defined, for now pick something a little 
00351   // bigger than IEEE underflow value
00352 
00353   double MinDiagonalValue = Epetra_MinDouble;
00354   double MaxDiagonalValue = 1.0/MinDiagonalValue;
00355 
00356   int ierr = 0;
00357   int i, j, k;
00358   int *LI, *UI;
00359   double *LV, *UV;
00360   int NumIn, NumL, NumU;
00361 
00362   // Get Maximun Row length
00363   int MaxNumEntries = L_->MaxNumEntries() + U_->MaxNumEntries() + 1;
00364 
00365   std::vector<int> InI(MaxNumEntries+1);    // Allocate temp space, pad by one to 
00366   std::vector<double> InV(MaxNumEntries+1); // to avoid debugger complaints for pathological cases
00367   std::vector<int> colflag(NumMyCols());
00368 
00369   double *DV;
00370   ierr = D_->ExtractView(&DV); // Get view of diagonal
00371 
00372 #ifdef IFPACK_FLOPCOUNTERS
00373   int current_madds = 0; // We will count multiply-add as they happen
00374 #endif
00375 
00376   // =========================== //
00377   // Now start the factorization //
00378   // =========================== //
00379 
00380   // Need some integer workspace and pointers
00381   int NumUU; 
00382   int * UUI;
00383   double * UUV;
00384   for (j = 0; j < NumMyCols(); ++j) colflag[j] = - 1;
00385 
00386   for (i = 0; i < NumMyRows(); ++i) {
00387 
00388     // Fill InV, InI with current row of L, D and U combined
00389 
00390     NumIn = MaxNumEntries;
00391     IFPACK_CHK_ERR(L_->ExtractMyRowCopy(i, NumIn, NumL, &InV[0], &InI[0]));
00392     LV = &InV[0];
00393     LI = &InI[0];
00394 
00395     InV[NumL] = DV[i]; // Put in diagonal
00396     InI[NumL] = i;
00397     
00398     IFPACK_CHK_ERR(U_->ExtractMyRowCopy(i, NumIn-NumL-1, NumU, &InV[NumL+1], &InI[NumL+1]));
00399     NumIn = NumL+NumU+1;
00400     UV = &InV[NumL+1];
00401     UI = &InI[NumL+1];
00402 
00403     // Set column flags
00404     for (j=0; j<NumIn; j++) colflag[InI[j]] = j;
00405 
00406     double diagmod = 0.0; // Off-diagonal accumulator
00407 
00408     for (int jj=0; jj<NumL; jj++) {
00409       j = InI[jj];
00410       double multiplier = InV[jj]; // current_mults++;
00411 
00412       InV[jj] *= DV[j];
00413       
00414       IFPACK_CHK_ERR(U_->ExtractMyRowView(j, NumUU, UUV, UUI)); // View of row above
00415 
00416       if (RelaxValue_==0.0) {
00417     for (k=0; k<NumUU; k++) {
00418       int kk = colflag[UUI[k]];
00419       if (kk>-1) {
00420         InV[kk] -= multiplier*UUV[k];
00421 #ifdef IFPACK_FLOPCOUNTERS
00422         current_madds++;
00423 #endif
00424       }
00425     }
00426       }
00427       else {
00428     for (k=0; k<NumUU; k++) {
00429       int kk = colflag[UUI[k]];
00430       if (kk>-1) InV[kk] -= multiplier*UUV[k];
00431       else diagmod -= multiplier*UUV[k];
00432 #ifdef IFPACK_FLOPCOUNTERS
00433       current_madds++;
00434 #endif
00435     }
00436       }
00437      }
00438     if (NumL) {
00439       IFPACK_CHK_ERR(L_->ReplaceMyValues(i, NumL, LV, LI));  // Replace current row of L
00440     }
00441 
00442     DV[i] = InV[NumL]; // Extract Diagonal value
00443 
00444     if (RelaxValue_!=0.0) {
00445       DV[i] += RelaxValue_*diagmod; // Add off diagonal modifications
00446       // current_madds++;
00447     }
00448 
00449     if (fabs(DV[i]) > MaxDiagonalValue) {
00450       if (DV[i] < 0) DV[i] = - MinDiagonalValue;
00451       else DV[i] = MinDiagonalValue;
00452     }
00453     else
00454       DV[i] = 1.0/DV[i]; // Invert diagonal value
00455 
00456     for (j=0; j<NumU; j++) UV[j] *= DV[i]; // Scale U by inverse of diagonal
00457 
00458     if (NumU) {
00459       IFPACK_CHK_ERR(U_->ReplaceMyValues(i, NumU, UV, UI));  // Replace current row of L and U
00460     }
00461 
00462     // Reset column flags
00463     for (j=0; j<NumIn; j++) colflag[InI[j]] = -1;
00464   }
00465 
00466   // Validate that the L and U factors are actually lower and upper triangular
00467 
00468   if (!L_->LowerTriangular()) 
00469     IFPACK_CHK_ERR(-4);
00470   if (!U_->UpperTriangular()) 
00471     IFPACK_CHK_ERR(-4);
00472   
00473 #ifdef IFPACK_FLOPCOUNTERS
00474   // Add up flops
00475  
00476   double current_flops = 2 * current_madds;
00477   double total_flops = 0;
00478     
00479   IFPACK_CHK_ERR(Graph().L_Graph().RowMap().Comm().SumAll(&current_flops, &total_flops, 1)); // Get total madds across all PEs
00480 
00481   // Now count the rest
00482   total_flops += (double) L_->NumGlobalNonzeros(); // Accounts for multiplier above
00483   total_flops += (double) D_->GlobalLength(); // Accounts for reciprocal of diagonal
00484   if (RelaxValue_!=0.0) total_flops += 2 * (double)D_->GlobalLength(); // Accounts for relax update of diag
00485 
00486   // add to this object's counter
00487   ComputeFlops_ += total_flops;
00488 #endif
00489   
00490   IsComputed_ = true;
00491   NumCompute_++;
00492   ComputeTime_ += Time_.ElapsedTime();
00493 
00494   return(ierr);
00495 
00496 }
00497 
00498 //=============================================================================
00499 // This function finds Y such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00500 int Ifpack_ILU::Solve(bool Trans, const Epetra_MultiVector& X, 
00501                       Epetra_MultiVector& Y) const 
00502 {
00503 
00504 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00505   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::ApplyInverse - Solve");
00506 #endif
00507 
00508   // in this function the overlap is always zero
00509   bool Upper = true;
00510   bool Lower = false;
00511   bool UnitDiagonal = true;
00512 
00513   if (!Trans) {
00514 
00515     IFPACK_CHK_ERR(L_->Solve(Lower, Trans, UnitDiagonal, X, Y));
00516     // y = D*y (D_ has inverse of diagonal)
00517     IFPACK_CHK_ERR(Y.Multiply(1.0, *D_, Y, 0.0)); 
00518     // Solve Uy = y
00519     IFPACK_CHK_ERR(U_->Solve(Upper, Trans, UnitDiagonal, Y, Y)); 
00520   }
00521   else {
00522     // Solve Uy = y
00523     IFPACK_CHK_ERR(U_->Solve(Upper, Trans, UnitDiagonal, X, Y)); 
00524     // y = D*y (D_ has inverse of diagonal)
00525     IFPACK_CHK_ERR(Y.Multiply(1.0, *D_, Y, 0.0)); 
00526     IFPACK_CHK_ERR(L_->Solve(Lower, Trans, UnitDiagonal, Y, Y));
00527   } 
00528 
00529 
00530   return(0);
00531 }
00532 
00533 //=============================================================================
00534 // This function finds X such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00535 int Ifpack_ILU::Multiply(bool Trans, const Epetra_MultiVector& X, 
00536                 Epetra_MultiVector& Y) const 
00537 {
00538 
00539 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00540   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::Multiply");
00541 #endif
00542 
00543   if (!IsComputed())
00544     IFPACK_CHK_ERR(-3);
00545 
00546   if (!Trans) {
00547     IFPACK_CHK_ERR(U_->Multiply(Trans, X, Y)); 
00548     // Y1 = Y1 + X1 (account for implicit unit diagonal)
00549     IFPACK_CHK_ERR(Y.Update(1.0, X, 1.0)); 
00550     // y = D*y (D_ has inverse of diagonal)
00551     IFPACK_CHK_ERR(Y.ReciprocalMultiply(1.0, *D_, Y, 0.0)); 
00552     Epetra_MultiVector Y1temp(Y); // Need a temp copy of Y1
00553     IFPACK_CHK_ERR(L_->Multiply(Trans, Y1temp, Y));
00554     // (account for implicit unit diagonal)
00555     IFPACK_CHK_ERR(Y.Update(1.0, Y1temp, 1.0)); 
00556   }
00557   else {
00558 
00559     IFPACK_CHK_ERR(L_->Multiply(Trans, X, Y));
00560     // Y1 = Y1 + X1 (account for implicit unit diagonal)
00561     IFPACK_CHK_ERR(Y.Update(1.0, X, 1.0)); 
00562     // y = D*y (D_ has inverse of diagonal)
00563     IFPACK_CHK_ERR(Y.ReciprocalMultiply(1.0, *D_, Y, 0.0)); 
00564     Epetra_MultiVector Y1temp(Y); // Need a temp copy of Y1
00565     IFPACK_CHK_ERR(U_->Multiply(Trans, Y1temp, Y));
00566     // (account for implicit unit diagonal)
00567     IFPACK_CHK_ERR(Y.Update(1.0, Y1temp, 1.0)); 
00568   } 
00569 
00570   return(0);
00571 }
00572 
00573 //=============================================================================
00574 // This function finds X such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00575 int Ifpack_ILU::ApplyInverse(const Epetra_MultiVector& X, 
00576                              Epetra_MultiVector& Y) const
00577 {
00578 
00579 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00580   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::ApplyInverse");
00581 #endif
00582 
00583   if (!IsComputed())
00584     IFPACK_CHK_ERR(-3);
00585 
00586   if (X.NumVectors() != Y.NumVectors())
00587     IFPACK_CHK_ERR(-2);
00588 
00589   Time_.ResetStartTime();
00590 
00591   // AztecOO gives X and Y pointing to the same memory location,
00592   // need to create an auxiliary vector, Xcopy
00593   Teuchos::RefCountPtr< const Epetra_MultiVector > Xcopy;
00594   if (X.Pointers()[0] == Y.Pointers()[0])
00595     Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) );
00596   else
00597     Xcopy = Teuchos::rcp( &X, false );
00598 
00599   IFPACK_CHK_ERR(Solve(Ifpack_ILU::UseTranspose(), *Xcopy, Y));
00600 
00601   // approx is the number of nonzeros in L and U
00602 #ifdef IFPACK_FLOPCOUNTERS
00603   ApplyInverseFlops_ += X.NumVectors() * 4 * 
00604     (L_->NumGlobalNonzeros() + U_->NumGlobalNonzeros());
00605 #endif
00606 
00607   ++NumApplyInverse_;
00608   ApplyInverseTime_ += Time_.ElapsedTime();
00609 
00610   return(0);
00611 
00612 }
00613 
00614 //=============================================================================
00615 double Ifpack_ILU::Condest(const Ifpack_CondestType CT, 
00616                            const int MaxIters, const double Tol,
00617                               Epetra_RowMatrix* Matrix_in)
00618 {
00619 
00620 #ifdef IFPACK_TEUCHOS_TIME_MONITOR
00621   TEUCHOS_FUNC_TIME_MONITOR("Ifpack_ILU::Condest");
00622 #endif
00623 
00624   if (!IsComputed()) // cannot compute right now
00625     return(-1.0);
00626 
00627   Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in);
00628 
00629   return(Condest_);
00630 }
00631 
00632 //=============================================================================
00633 std::ostream&
00634 Ifpack_ILU::Print(std::ostream& os) const
00635 {
00636   if (!Comm().MyPID()) {
00637     os << endl;
00638     os << "================================================================================" << endl;
00639     os << "Ifpack_ILU: " << Label() << endl << endl;
00640     os << "Level-of-fill      = " << LevelOfFill() << endl;
00641     os << "Absolute threshold = " << AbsoluteThreshold() << endl;
00642     os << "Relative threshold = " << RelativeThreshold() << endl;
00643     os << "Relax value        = " << RelaxValue() << endl;
00644     os << "Condition number estimate = " << Condest() << endl;
00645     os << "Global number of rows            = " << A_->NumGlobalRows64() << endl;
00646     if (IsComputed_) {
00647       os << "Number of rows of L, D, U       = " << L_->NumGlobalRows64() << endl;
00648       os << "Number of nonzeros of L + U     = " << NumGlobalNonzeros64() << endl;
00649       os << "nonzeros / rows                 = " 
00650         << 1.0 * NumGlobalNonzeros64() / U_->NumGlobalRows64() << endl;
00651     }
00652     os << endl;
00653     os << "Phase           # calls   Total Time (s)       Total MFlops     MFlops/s" << endl;
00654     os << "-----           -------   --------------       ------------     --------" << endl;
00655     os << "Initialize()    "   << std::setw(5) << NumInitialize() 
00656        << "  " << std::setw(15) << InitializeTime() 
00657        << "               0.0            0.0" << endl;
00658     os << "Compute()       "   << std::setw(5) << NumCompute() 
00659        << "  " << std::setw(15) << ComputeTime()
00660        << "  " << std::setw(15) << 1.0e-6 * ComputeFlops();
00661     if (ComputeTime() != 0.0) 
00662       os << "  " << std::setw(15) << 1.0e-6 * ComputeFlops() / ComputeTime() << endl;
00663     else
00664       os << "  " << std::setw(15) << 0.0 << endl;
00665     os << "ApplyInverse()  "   << std::setw(5) << NumApplyInverse() 
00666        << "  " << std::setw(15) << ApplyInverseTime()
00667        << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops();
00668     if (ApplyInverseTime() != 0.0) 
00669       os << "  " << std::setw(15) << 1.0e-6 * ApplyInverseFlops() / ApplyInverseTime() << endl;
00670     else
00671       os << "  " << std::setw(15) << 0.0 << endl;
00672     os << "================================================================================" << endl;
00673     os << endl;
00674   }
00675 
00676   return(os);
00677 }
 All Classes Files Functions Variables Enumerations Friends