IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_CrsRiluk.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 #include "Ifpack_CrsRiluk.h"
00043 #include "Epetra_ConfigDefs.h"
00044 #include "Epetra_Comm.h"
00045 #include "Epetra_Map.h"
00046 #include "Epetra_CrsGraph.h"
00047 #include "Epetra_VbrMatrix.h"
00048 #include "Epetra_RowMatrix.h"
00049 #include "Epetra_MultiVector.h"
00050 
00051 #include <Teuchos_ParameterList.hpp>
00052 #include <ifp_parameters.h>
00053 
00054 //==============================================================================
00055 Ifpack_CrsRiluk::Ifpack_CrsRiluk(const Ifpack_IlukGraph & Graph_in) 
00056   : UserMatrixIsVbr_(false),
00057     UserMatrixIsCrs_(false),
00058     Graph_(Graph_in),
00059     Comm_(Graph_in.Comm()),
00060     UseTranspose_(false),
00061     NumMyDiagonals_(0),
00062     Allocated_(false),
00063     ValuesInitialized_(false),
00064     Factored_(false),
00065     RelaxValue_(0.0),
00066     Athresh_(0.0),
00067     Rthresh_(1.0),
00068     Condest_(-1.0),
00069     OverlapMode_(Zero)
00070 {
00071   // Test for non-trivial overlap here so we can use it later.
00072   IsOverlapped_ = (Graph_in.LevelOverlap()>0 && Graph_in.DomainMap().DistributedGlobal());
00073 }
00074 
00075 //==============================================================================
00076 Ifpack_CrsRiluk::Ifpack_CrsRiluk(const Ifpack_CrsRiluk & FactoredMatrix) 
00077   : UserMatrixIsVbr_(FactoredMatrix.UserMatrixIsVbr_),
00078     UserMatrixIsCrs_(FactoredMatrix.UserMatrixIsCrs_),
00079     IsOverlapped_(FactoredMatrix.IsOverlapped_),
00080     Graph_(FactoredMatrix.Graph_),
00081     IlukRowMap_(FactoredMatrix.IlukRowMap_),
00082     IlukDomainMap_(FactoredMatrix.IlukDomainMap_),
00083     IlukRangeMap_(FactoredMatrix.IlukRangeMap_),
00084     Comm_(FactoredMatrix.Comm_),
00085     UseTranspose_(FactoredMatrix.UseTranspose_),
00086     NumMyDiagonals_(FactoredMatrix.NumMyDiagonals_),
00087     Allocated_(FactoredMatrix.Allocated_),
00088     ValuesInitialized_(FactoredMatrix.ValuesInitialized_),
00089     Factored_(FactoredMatrix.Factored_),
00090     RelaxValue_(FactoredMatrix.RelaxValue_),
00091     Athresh_(FactoredMatrix.Athresh_),
00092     Rthresh_(FactoredMatrix.Rthresh_),
00093     Condest_(FactoredMatrix.Condest_),
00094     OverlapMode_(FactoredMatrix.OverlapMode_)
00095 {
00096   L_ = Teuchos::rcp( new Epetra_CrsMatrix(FactoredMatrix.L()) );
00097   U_ = Teuchos::rcp( new Epetra_CrsMatrix(FactoredMatrix.U()) );
00098   D_ = Teuchos::rcp( new Epetra_Vector(FactoredMatrix.D()) );
00099   if (IlukRowMap_!=Teuchos::null) IlukRowMap_ = Teuchos::rcp( new Epetra_Map(*IlukRowMap_) );
00100   if (IlukDomainMap_!=Teuchos::null) IlukDomainMap_ = Teuchos::rcp( new Epetra_Map(*IlukDomainMap_) );
00101   if (IlukRangeMap_!=Teuchos::null) IlukRangeMap_ = Teuchos::rcp( new Epetra_Map(*IlukRangeMap_) );
00102   
00103 }
00104 //==============================================================================
00105 Ifpack_CrsRiluk::~Ifpack_CrsRiluk(){
00106 
00107   ValuesInitialized_ = false;
00108   Factored_ = false;
00109   Allocated_ = false;
00110 }
00111 //==============================================================================
00112 int Ifpack_CrsRiluk::AllocateCrs() {
00113 
00114   // Allocate Epetra_CrsMatrix using ILUK graphs
00115   L_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy, Graph_.L_Graph()) );
00116   U_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy, Graph_.U_Graph()) );
00117   D_ = Teuchos::rcp( new Epetra_Vector(Graph_.L_Graph().RowMap()) );
00118   L_Graph_ = Teuchos::null;
00119   U_Graph_ = Teuchos::null;
00120   SetAllocated(true);
00121   return(0);
00122 }
00123 //==============================================================================
00124 int Ifpack_CrsRiluk::AllocateVbr() {
00125 
00126   // First we need to create a set of Epetra_Maps that has the same number of points  as the
00127   // Epetra_BlockMaps associated with the Overlap Graph.
00128   EPETRA_CHK_ERR(BlockMap2PointMap(Graph_.L_Graph().RowMap(), &IlukRowMap_));
00129   EPETRA_CHK_ERR(BlockMap2PointMap(Graph_.U_Graph().DomainMap(), &IlukDomainMap_));
00130   EPETRA_CHK_ERR(BlockMap2PointMap(Graph_.L_Graph().RangeMap(), &IlukRangeMap_));
00131 
00132   // Set L range map and U domain map
00133   U_DomainMap_ = IlukDomainMap_;
00134   L_RangeMap_ = IlukRangeMap_;
00135   // If there is fill, then pre-build the L and U structures from the Block version of L and U.
00136   if (Graph().LevelFill()) { 
00137     L_Graph_ = Teuchos::rcp( new Epetra_CrsGraph(Copy, *IlukRowMap_, *IlukRowMap_, 0) );
00138     U_Graph_ = Teuchos::rcp( new Epetra_CrsGraph(Copy, *IlukRowMap_, *IlukRowMap_, 0) );
00139     EPETRA_CHK_ERR(BlockGraph2PointGraph(Graph_.L_Graph(), *L_Graph_, false));
00140     EPETRA_CHK_ERR(BlockGraph2PointGraph(Graph_.U_Graph(), *U_Graph_, true));
00141     
00142     L_Graph_->FillComplete(*IlukRowMap_, *IlukRangeMap_);
00143     U_Graph_->FillComplete(*IlukDomainMap_, *IlukRowMap_);
00144 
00145     L_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy, *L_Graph_) );
00146     U_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy, *U_Graph_) );
00147     D_ = Teuchos::rcp( new Epetra_Vector(*IlukRowMap_) );
00148   }
00149   else {
00150     // Allocate Epetra_CrsMatrix using ILUK graphs
00151     L_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy, *IlukRowMap_, *IlukRowMap_, 0) );
00152     U_ = Teuchos::rcp( new Epetra_CrsMatrix(Copy, *IlukRowMap_, *IlukRowMap_, 0) );
00153     D_ = Teuchos::rcp( new Epetra_Vector(*IlukRowMap_) );
00154     L_Graph_ = Teuchos::null;
00155     U_Graph_ = Teuchos::null;
00156   }
00157   SetAllocated(true);
00158   return(0);
00159 }
00160 
00161 //==========================================================================
00162 int Ifpack_CrsRiluk::SetParameters(const Teuchos::ParameterList& parameterlist,
00163                                    bool cerr_warning_if_unused)
00164 {
00165   Ifpack::param_struct params;
00166   params.double_params[Ifpack::relax_value] = RelaxValue_;
00167   params.double_params[Ifpack::absolute_threshold] = Athresh_;
00168   params.double_params[Ifpack::relative_threshold] = Rthresh_;
00169   params.overlap_mode = OverlapMode_;
00170 
00171   Ifpack::set_parameters(parameterlist, params, cerr_warning_if_unused);
00172 
00173   RelaxValue_ = params.double_params[Ifpack::relax_value];
00174   Athresh_ = params.double_params[Ifpack::absolute_threshold];
00175   Rthresh_ = params.double_params[Ifpack::relative_threshold];
00176   OverlapMode_ = params.overlap_mode;
00177 
00178   return(0);
00179 }
00180 
00181 //==========================================================================
00182 int Ifpack_CrsRiluk::InitValues(const Epetra_CrsMatrix & A) {
00183 
00184   UserMatrixIsCrs_ = true;
00185 
00186   if (!Allocated()) AllocateCrs();
00187 
00188   Teuchos::RefCountPtr<Epetra_CrsMatrix> OverlapA = Teuchos::rcp( (Epetra_CrsMatrix *) &A, false );
00189 
00190   if (IsOverlapped_) {
00191   
00192     OverlapA = Teuchos::rcp( new Epetra_CrsMatrix(Copy, *Graph_.OverlapGraph()) );
00193     EPETRA_CHK_ERR(OverlapA->Import(A, *Graph_.OverlapImporter(), Insert));
00194     EPETRA_CHK_ERR(OverlapA->FillComplete());
00195   }
00196   
00197   // Get Maximun Row length
00198   int MaxNumEntries = OverlapA->MaxNumEntries();
00199 
00200   // Set L range map and U domain map
00201   U_DomainMap_ = Teuchos::rcp( &(A.DomainMap()), false );
00202   L_RangeMap_ = Teuchos::rcp( &(A.RangeMap()), false );
00203   // Do the rest using generic Epetra_RowMatrix interface
00204 
00205   EPETRA_CHK_ERR(InitAllValues(*OverlapA, MaxNumEntries));
00206 
00207   return(0);
00208 }
00209 
00210 //==========================================================================
00211 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES // FIXME LONG LONG
00212 int Ifpack_CrsRiluk::InitValues(const Epetra_VbrMatrix & A) {
00213 
00214   UserMatrixIsVbr_ = true;
00215 
00216   if (!Allocated()) AllocateVbr();
00217 
00218   //cout << "Original Graph " << endl <<  A.Graph() << endl << flush;
00219   //A.Comm().Barrier(); 
00220   //if (A.Comm().MyPID()==0) cout << "*****************************************************" <<endl;
00221   //cout << "Original Matrix " << endl << A << endl << flush;
00222   //A.Comm().Barrier(); 
00223   //if (A.Comm().MyPID()==0) cout << "*****************************************************" <<endl;
00224   //cout << "Overlap Graph " << endl << *Graph_.OverlapGraph() << endl << flush;
00225   //A.Comm().Barrier(); 
00226   //if (A.Comm().MyPID()==0) cout << "*****************************************************" <<endl;
00227 
00228   Teuchos::RefCountPtr<Epetra_VbrMatrix> OverlapA = Teuchos::rcp( (Epetra_VbrMatrix *) &A, false );
00229 
00230   if (IsOverlapped_) {
00231   
00232     OverlapA = Teuchos::rcp( new Epetra_VbrMatrix(Copy, *Graph_.OverlapGraph()) );
00233     EPETRA_CHK_ERR(OverlapA->Import(A, *Graph_.OverlapImporter(), Insert));
00234     EPETRA_CHK_ERR(OverlapA->FillComplete());
00235   }
00236   
00237   //cout << "Overlap Matrix " << endl << *OverlapA << endl << flush;
00238 
00239   // Get Maximun Row length
00240   int MaxNumEntries = OverlapA->MaxNumNonzeros();
00241 
00242   // Do the rest using generic Epetra_RowMatrix interface
00243 
00244   EPETRA_CHK_ERR(InitAllValues(*OverlapA, MaxNumEntries));
00245 
00246   return(0);
00247 }
00248 #endif
00249 //==========================================================================
00250 
00251 int Ifpack_CrsRiluk::InitAllValues(const Epetra_RowMatrix & OverlapA, int MaxNumEntries) {
00252 
00253   int ierr = 0;
00254   int i, j;
00255   int NumIn, NumL, NumU;
00256   bool DiagFound;
00257   int NumNonzeroDiags = 0;
00258 
00259 
00260   std::vector<int> InI(MaxNumEntries); // Allocate temp space
00261   std::vector<int> LI(MaxNumEntries);
00262   std::vector<int> UI(MaxNumEntries);
00263   std::vector<double> InV(MaxNumEntries);
00264   std::vector<double> LV(MaxNumEntries);
00265   std::vector<double> UV(MaxNumEntries);
00266 
00267   bool ReplaceValues = (L_->StaticGraph() || L_->IndicesAreLocal()); // Check if values should be inserted or replaced
00268 
00269   if (ReplaceValues) {
00270     L_->PutScalar(0.0); // Zero out L and U matrices
00271     U_->PutScalar(0.0);
00272   }
00273 
00274   D_->PutScalar(0.0); // Set diagonal values to zero
00275   double *DV;
00276   EPETRA_CHK_ERR(D_->ExtractView(&DV)); // Get view of diagonal
00277     
00278 
00279   // First we copy the user's matrix into L and U, regardless of fill level
00280 
00281   for (i=0; i< NumMyRows(); i++) {
00282 
00283     EPETRA_CHK_ERR(OverlapA.ExtractMyRowCopy(i, MaxNumEntries, NumIn, &InV[0], &InI[0])); // Get Values and Indices
00284     
00285     // Split into L and U (we don't assume that indices are ordered).
00286     
00287     NumL = 0; 
00288     NumU = 0; 
00289     DiagFound = false;
00290     
00291     for (j=0; j< NumIn; j++) {
00292       int k = InI[j];
00293 
00294       if (k==i) {
00295     DiagFound = true;
00296     DV[i] += Rthresh_ * InV[j] + EPETRA_SGN(InV[j]) * Athresh_; // Store perturbed diagonal in Epetra_Vector D_
00297       }
00298 
00299       else if (k < 0) {EPETRA_CHK_ERR(-1);} // Out of range
00300 
00301       else if (k < i) {
00302     LI[NumL] = k;
00303     LV[NumL] = InV[j];
00304     NumL++;
00305       }
00306       else if (k<NumMyRows()) {
00307     UI[NumU] = k;
00308     UV[NumU] = InV[j];
00309     NumU++;
00310       }
00311     }
00312     
00313     // Check in things for this row of L and U
00314 
00315     if (DiagFound) NumNonzeroDiags++;
00316     else DV[i] = Athresh_;
00317 
00318     if (NumL) {
00319       if (ReplaceValues) {
00320     EPETRA_CHK_ERR(L_->ReplaceMyValues(i, NumL, &LV[0], &LI[0]));
00321       }
00322       else {
00323     EPETRA_CHK_ERR(L_->InsertMyValues(i, NumL, &LV[0], &LI[0]));
00324       }
00325     }
00326 
00327     if (NumU) {
00328       if (ReplaceValues) {
00329     EPETRA_CHK_ERR(U_->ReplaceMyValues(i, NumU, &UV[0], &UI[0]));
00330       }
00331       else {
00332     EPETRA_CHK_ERR(U_->InsertMyValues(i, NumU, &UV[0], &UI[0]));
00333       }
00334     }
00335     
00336   }
00337 
00338   if (!ReplaceValues) {
00339     // The domain of L and the range of U are exactly their own row maps (there is no communication).
00340     // The domain of U and the range of L must be the same as those of the original matrix,
00341     // However if the original matrix is a VbrMatrix, these two latter maps are translation from
00342     // a block map to a point map.
00343     EPETRA_CHK_ERR(L_->FillComplete(L_->RowMatrixColMap(), *L_RangeMap_));
00344     EPETRA_CHK_ERR(U_->FillComplete(*U_DomainMap_, U_->RowMatrixRowMap()));
00345   }
00346 
00347   // At this point L and U have the values of A in the structure of L and U, and diagonal vector D
00348 
00349   SetValuesInitialized(true);
00350   SetFactored(false);
00351 
00352   int TotalNonzeroDiags = 0;
00353   EPETRA_CHK_ERR(Graph_.L_Graph().RowMap().Comm().SumAll(&NumNonzeroDiags, &TotalNonzeroDiags, 1));
00354   NumMyDiagonals_ = NumNonzeroDiags;
00355   if (NumNonzeroDiags != NumMyRows()) ierr = 1; // Diagonals are not right, warn user
00356 
00357   return(ierr);
00358 }
00359 
00360 //==========================================================================
00361 int Ifpack_CrsRiluk::Factor() {
00362 
00363   // if (!Allocated()) return(-1); // This test is not needed at this time.  All constructors allocate.
00364   if (!ValuesInitialized()) return(-2); // Must have values initialized.
00365   if (Factored()) return(-3); // Can't have already computed factors.
00366 
00367   SetValuesInitialized(false);
00368 
00369   // MinMachNum should be officially defined, for now pick something a little 
00370   // bigger than IEEE underflow value
00371 
00372   double MinDiagonalValue = Epetra_MinDouble;
00373   double MaxDiagonalValue = 1.0/MinDiagonalValue;
00374 
00375   int ierr = 0;
00376   int i, j, k;
00377   int * LI=0, * UI = 0;
00378   double * LV=0, * UV = 0;
00379   int NumIn, NumL, NumU;
00380 
00381   // Get Maximun Row length
00382   int MaxNumEntries = L_->MaxNumEntries() + U_->MaxNumEntries() + 1;
00383 
00384   std::vector<int> InI(MaxNumEntries); // Allocate temp space
00385   std::vector<double> InV(MaxNumEntries);
00386   std::vector<int> colflag(NumMyCols());
00387 
00388   double *DV;
00389   ierr = D_->ExtractView(&DV); // Get view of diagonal
00390 
00391 #ifdef IFPACK_FLOPCOUNTERS
00392   int current_madds = 0; // We will count multiply-add as they happen
00393 #endif
00394 
00395   // Now start the factorization.
00396 
00397   // Need some integer workspace and pointers
00398   int NumUU; 
00399   int * UUI;
00400   double * UUV;
00401   for (j=0; j<NumMyCols(); j++) colflag[j] = - 1;
00402 
00403   for(i=0; i<NumMyRows(); i++) {
00404 
00405  // Fill InV, InI with current row of L, D and U combined
00406 
00407     NumIn = MaxNumEntries;
00408     EPETRA_CHK_ERR(L_->ExtractMyRowCopy(i, NumIn, NumL, &InV[0], &InI[0]));
00409     LV = &InV[0];
00410     LI = &InI[0];
00411 
00412     InV[NumL] = DV[i]; // Put in diagonal
00413     InI[NumL] = i;
00414     
00415     EPETRA_CHK_ERR(U_->ExtractMyRowCopy(i, NumIn-NumL-1, NumU, &InV[NumL+1], &InI[NumL+1]));
00416     NumIn = NumL+NumU+1;
00417     UV = &InV[NumL+1];
00418     UI = &InI[NumL+1];
00419 
00420     // Set column flags
00421     for (j=0; j<NumIn; j++) colflag[InI[j]] = j;
00422 
00423     double diagmod = 0.0; // Off-diagonal accumulator
00424 
00425     for (int jj=0; jj<NumL; jj++) {
00426       j = InI[jj];
00427       double multiplier = InV[jj]; // current_mults++;
00428 
00429       InV[jj] *= DV[j];
00430       
00431       EPETRA_CHK_ERR(U_->ExtractMyRowView(j, NumUU, UUV, UUI)); // View of row above
00432 
00433       if (RelaxValue_==0.0) {
00434     for (k=0; k<NumUU; k++) {
00435       int kk = colflag[UUI[k]];
00436       if (kk>-1) {
00437         InV[kk] -= multiplier*UUV[k];
00438 #ifdef IFPACK_FLOPCOUNTERS
00439         current_madds++;
00440 #endif
00441       }
00442     }
00443       }
00444       else {
00445     for (k=0; k<NumUU; k++) {
00446       int kk = colflag[UUI[k]];
00447       if (kk>-1) InV[kk] -= multiplier*UUV[k];
00448       else diagmod -= multiplier*UUV[k];
00449 #ifdef IFPACK_FLOPCOUNTERS
00450       current_madds++;
00451 #endif
00452     }
00453       }
00454      }
00455     if (NumL) {
00456       EPETRA_CHK_ERR(L_->ReplaceMyValues(i, NumL, LV, LI));  // Replace current row of L
00457     }
00458 
00459     DV[i] = InV[NumL]; // Extract Diagonal value
00460 
00461     if (RelaxValue_!=0.0) {
00462       DV[i] += RelaxValue_*diagmod; // Add off diagonal modifications
00463       // current_madds++;
00464     }
00465 
00466     if (fabs(DV[i]) > MaxDiagonalValue) {
00467       if (DV[i] < 0) DV[i] = - MinDiagonalValue;
00468       else DV[i] = MinDiagonalValue;
00469     }
00470     else
00471       DV[i] = 1.0/DV[i]; // Invert diagonal value
00472 
00473     for (j=0; j<NumU; j++) UV[j] *= DV[i]; // Scale U by inverse of diagonal
00474 
00475     if (NumU) {
00476       EPETRA_CHK_ERR(U_->ReplaceMyValues(i, NumU, UV, UI));  // Replace current row of L and U
00477     }
00478 
00479     // Reset column flags
00480     for (j=0; j<NumIn; j++) colflag[InI[j]] = -1;
00481   }
00482 
00483   // Validate that the L and U factors are actually lower and upper triangular
00484 
00485   if( !L_->LowerTriangular() ) 
00486     EPETRA_CHK_ERR(-2);
00487   if( !U_->UpperTriangular() ) 
00488     EPETRA_CHK_ERR(-3);
00489   
00490 #ifdef IFPACK_FLOPCOUNTERS
00491   // Add up flops
00492  
00493   double current_flops = 2 * current_madds;
00494   double total_flops = 0;
00495     
00496   EPETRA_CHK_ERR(Graph_.L_Graph().RowMap().Comm().SumAll(&current_flops, &total_flops, 1)); // Get total madds across all PEs
00497 
00498   // Now count the rest
00499   total_flops += (double) L_->NumGlobalNonzeros(); // Accounts for multiplier above
00500   total_flops += (double) D_->GlobalLength(); // Accounts for reciprocal of diagonal
00501   if (RelaxValue_!=0.0) total_flops += 2 * (double)D_->GlobalLength(); // Accounts for relax update of diag
00502 
00503   UpdateFlops(total_flops); // Update flop count
00504 #endif
00505 
00506   SetFactored(true);
00507 
00508   return(ierr);
00509 
00510 }
00511 
00512 //=============================================================================
00513 int Ifpack_CrsRiluk::Solve(bool Trans, const Epetra_MultiVector& X, 
00514                 Epetra_MultiVector& Y) const {
00515 //
00516 // This function finds Y such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00517 //
00518 
00519   // First generate X and Y as needed for this function
00520   Teuchos::RefCountPtr<Epetra_MultiVector> X1;
00521   Teuchos::RefCountPtr<Epetra_MultiVector> Y1;
00522   EPETRA_CHK_ERR(GenerateXY(Trans, X, Y, &X1, &Y1));
00523 
00524   bool Upper = true;
00525   bool Lower = false;
00526   bool UnitDiagonal = true;
00527 
00528 #ifdef IFPACK_FLOPCOUNTERS
00529   Epetra_Flops * counter = this->GetFlopCounter();
00530   if (counter!=0) {
00531     L_->SetFlopCounter(*counter);
00532     Y1->SetFlopCounter(*counter);
00533     U_->SetFlopCounter(*counter);
00534   }
00535 #endif
00536 
00537   if (!Trans) {
00538 
00539     EPETRA_CHK_ERR(L_->Solve(Lower, Trans, UnitDiagonal, *X1, *Y1));
00540     EPETRA_CHK_ERR(Y1->Multiply(1.0, *D_, *Y1, 0.0)); // y = D*y (D_ has inverse of diagonal)
00541     EPETRA_CHK_ERR(U_->Solve(Upper, Trans, UnitDiagonal, *Y1, *Y1)); // Solve Uy = y
00542     if (IsOverlapped_) {EPETRA_CHK_ERR(Y.Export(*Y1,*L_->Exporter(), OverlapMode_));} // Export computed Y values if needed
00543   }
00544   else {
00545     EPETRA_CHK_ERR(U_->Solve(Upper, Trans, UnitDiagonal, *X1, *Y1)); // Solve Uy = y
00546     EPETRA_CHK_ERR(Y1->Multiply(1.0, *D_, *Y1, 0.0)); // y = D*y (D_ has inverse of diagonal)
00547     EPETRA_CHK_ERR(L_->Solve(Lower, Trans, UnitDiagonal, *Y1, *Y1));
00548     if (IsOverlapped_) {EPETRA_CHK_ERR(Y.Export(*Y1,*U_->Importer(), OverlapMode_));} // Export computed Y values if needed
00549   } 
00550 
00551   return(0);
00552 }
00553 //=============================================================================
00554 int Ifpack_CrsRiluk::Multiply(bool Trans, const Epetra_MultiVector& X, 
00555                   Epetra_MultiVector& Y) const {
00556 //
00557 // This function finds X such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS
00558 //
00559     
00560   // First generate X and Y as needed for this function
00561   Teuchos::RefCountPtr<Epetra_MultiVector> X1;
00562   Teuchos::RefCountPtr<Epetra_MultiVector> Y1;
00563   EPETRA_CHK_ERR(GenerateXY(Trans, X, Y, &X1, &Y1));
00564 
00565 #ifdef IFPACK_FLOPCOUNTERS
00566   Epetra_Flops * counter = this->GetFlopCounter();
00567   if (counter!=0) {
00568     L_->SetFlopCounter(*counter);
00569     Y1->SetFlopCounter(*counter);
00570     U_->SetFlopCounter(*counter);
00571   }
00572 #endif
00573 
00574   if (!Trans) {
00575     EPETRA_CHK_ERR(U_->Multiply(Trans, *X1, *Y1)); // 
00576     EPETRA_CHK_ERR(Y1->Update(1.0, *X1, 1.0)); // Y1 = Y1 + X1 (account for implicit unit diagonal)
00577     EPETRA_CHK_ERR(Y1->ReciprocalMultiply(1.0, *D_, *Y1, 0.0)); // y = D*y (D_ has inverse of diagonal)
00578     Epetra_MultiVector Y1temp(*Y1); // Need a temp copy of Y1
00579     EPETRA_CHK_ERR(L_->Multiply(Trans, Y1temp, *Y1));
00580     EPETRA_CHK_ERR(Y1->Update(1.0, Y1temp, 1.0)); // (account for implicit unit diagonal)
00581     if (IsOverlapped_) {EPETRA_CHK_ERR(Y.Export(*Y1,*L_->Exporter(), OverlapMode_));} // Export computed Y values if needed
00582   }
00583   else {
00584 
00585     EPETRA_CHK_ERR(L_->Multiply(Trans, *X1, *Y1));
00586     EPETRA_CHK_ERR(Y1->Update(1.0, *X1, 1.0)); // Y1 = Y1 + X1 (account for implicit unit diagonal)
00587     EPETRA_CHK_ERR(Y1->ReciprocalMultiply(1.0, *D_, *Y1, 0.0)); // y = D*y (D_ has inverse of diagonal)
00588     Epetra_MultiVector Y1temp(*Y1); // Need a temp copy of Y1
00589     EPETRA_CHK_ERR(U_->Multiply(Trans, Y1temp, *Y1));
00590     EPETRA_CHK_ERR(Y1->Update(1.0, Y1temp, 1.0)); // (account for implicit unit diagonal)
00591     if (IsOverlapped_) {EPETRA_CHK_ERR(Y.Export(*Y1,*L_->Exporter(), OverlapMode_));}
00592   } 
00593   return(0);
00594 }
00595 //=============================================================================
00596 int Ifpack_CrsRiluk::Condest(bool Trans, double & ConditionNumberEstimate) const {
00597 
00598   if (Condest_>=0.0) {
00599     ConditionNumberEstimate = Condest_;
00600     return(0);
00601   }
00602   // Create a vector with all values equal to one
00603   Epetra_Vector Ones(U_->DomainMap());
00604   Epetra_Vector OnesResult(L_->RangeMap());
00605   Ones.PutScalar(1.0);
00606 
00607   EPETRA_CHK_ERR(Solve(Trans, Ones, OnesResult)); // Compute the effect of the solve on the vector of ones
00608   EPETRA_CHK_ERR(OnesResult.Abs(OnesResult)); // Make all values non-negative
00609   EPETRA_CHK_ERR(OnesResult.MaxValue(&ConditionNumberEstimate)); // Get the maximum value across all processors
00610   Condest_ = ConditionNumberEstimate; // Save value for possible later calls
00611   return(0);
00612 }
00613 //==============================================================================
00614 int Ifpack_CrsRiluk::BlockGraph2PointGraph(const Epetra_CrsGraph & BG, Epetra_CrsGraph & PG, bool Upper) {
00615 
00616   if (!BG.IndicesAreLocal()) {EPETRA_CHK_ERR(-1);} // Must have done FillComplete on BG
00617 
00618   int * ColFirstPointInElementList = BG.RowMap().FirstPointInElementList();
00619   int * ColElementSizeList = BG.RowMap().ElementSizeList();
00620   if (BG.Importer()!=0) {
00621     ColFirstPointInElementList = BG.ImportMap().FirstPointInElementList();
00622     ColElementSizeList = BG.ImportMap().ElementSizeList();
00623   }
00624 
00625   int Length = (BG.MaxNumIndices()+1) * BG.ImportMap().MaxMyElementSize();
00626   std::vector<int> tmpIndices(Length);
00627 
00628   int BlockRow, BlockOffset, NumEntries;
00629   int NumBlockEntries;
00630   int * BlockIndices;
00631 
00632   int NumMyRows_tmp = PG.NumMyRows();
00633 
00634   for (int i=0; i<NumMyRows_tmp; i++) {
00635     EPETRA_CHK_ERR(BG.RowMap().FindLocalElementID(i, BlockRow, BlockOffset));
00636     EPETRA_CHK_ERR(BG.ExtractMyRowView(BlockRow, NumBlockEntries, BlockIndices));
00637 
00638     int * ptr = &tmpIndices[0]; // Set pointer to beginning of buffer
00639 
00640     int RowDim = BG.RowMap().ElementSize(BlockRow);
00641     NumEntries = 0;
00642 
00643     // This next line make sure that the off-diagonal entries in the block diagonal of the 
00644     // original block entry matrix are included in the nonzero pattern of the point graph
00645     if (Upper) {
00646       int jstart = i+1;
00647       int jstop = EPETRA_MIN(NumMyRows_tmp,i+RowDim-BlockOffset);
00648       for (int j= jstart; j< jstop; j++) {*ptr++ = j; NumEntries++;}
00649     }
00650 
00651     for (int j=0; j<NumBlockEntries; j++) {
00652       int ColDim = ColElementSizeList[BlockIndices[j]];
00653       NumEntries += ColDim;
00654       assert(NumEntries<=Length); // Sanity test
00655       int Index = ColFirstPointInElementList[BlockIndices[j]];
00656       for (int k=0; k < ColDim; k++) *ptr++ = Index++;
00657     }
00658 
00659     // This next line make sure that the off-diagonal entries in the block diagonal of the 
00660     // original block entry matrix are included in the nonzero pattern of the point graph
00661     if (!Upper) {
00662       int jstart = EPETRA_MAX(0,i-RowDim+1);
00663       int jstop = i;
00664       for (int j = jstart; j < jstop; j++) {*ptr++ = j; NumEntries++;}
00665     }
00666 
00667     EPETRA_CHK_ERR(PG.InsertMyIndices(i, NumEntries, &tmpIndices[0]));
00668   }
00669 
00670   SetAllocated(true);
00671 
00672   return(0);
00673 }
00674 //=========================================================================
00675 int Ifpack_CrsRiluk::BlockMap2PointMap(const Epetra_BlockMap & BlockMap, Teuchos::RefCountPtr<Epetra_Map>* PointMap) {
00676     // Generate an Epetra_Map that has the same number and distribution of points
00677     // as the input Epetra_BlockMap object.  The global IDs for the output PointMap
00678     // are computed by using the MaxElementSize of the BlockMap.  For variable block
00679     // sizes this will create gaps in the GID space, but that is OK for Epetra_Maps.
00680 
00681     int MaxElementSize = BlockMap.MaxElementSize();
00682     int PtNumMyElements = BlockMap.NumMyPoints();
00683 
00684     std::vector<int> PtMyGlobalElements_int;
00685     std::vector<long long> PtMyGlobalElements_LL;
00686 
00687     int NumMyElements = BlockMap.NumMyElements();
00688     int curID = 0;
00689 
00690     if (PtNumMyElements>0) {
00691 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00692       if(BlockMap.GlobalIndicesInt()) {
00693         PtMyGlobalElements_int.resize(PtNumMyElements);
00694         for (int i=0; i<NumMyElements; i++) {
00695           int StartID = BlockMap.GID(i)*MaxElementSize;
00696           int ElementSize = BlockMap.ElementSize(i);
00697           for (int j=0; j<ElementSize; j++) PtMyGlobalElements_int[curID++] = StartID+j;
00698         }
00699       }
00700       else
00701 #endif
00702 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00703       if(BlockMap.GlobalIndicesLongLong()) {
00704         PtMyGlobalElements_LL.resize(PtNumMyElements);
00705         for (int i=0; i<NumMyElements; i++) {
00706           long long StartID = BlockMap.GID64(i)*MaxElementSize;
00707           int ElementSize = BlockMap.ElementSize(i);
00708           for (int j=0; j<ElementSize; j++) PtMyGlobalElements_LL[curID++] = StartID+j;
00709         }
00710       }
00711       else
00712 #endif
00713         throw "Ifpack_CrsRiluk::BlockMap2PointMap: GlobalIndices type unknown";
00714     }
00715 
00716     assert(curID==PtNumMyElements); // Sanity test
00717 
00718 #ifndef EPETRA_NO_32BIT_GLOBAL_INDICES
00719     if(BlockMap.GlobalIndicesInt())
00720       (*PointMap) = Teuchos::rcp( new Epetra_Map(-1, PtNumMyElements, &PtMyGlobalElements_int[0], BlockMap.IndexBase(), BlockMap.Comm()) );
00721     else
00722 #endif
00723 #ifndef EPETRA_NO_64BIT_GLOBAL_INDICES
00724     if(BlockMap.GlobalIndicesLongLong())
00725       (*PointMap) = Teuchos::rcp( new Epetra_Map(-1LL, PtNumMyElements, &PtMyGlobalElements_LL[0], BlockMap.IndexBase64(), BlockMap.Comm()) );
00726     else
00727 #endif
00728       throw "Ifpack_CrsRiluk::BlockMap2PointMap: GlobalIndices type unknown";
00729 
00730     if (!BlockMap.PointSameAs(*(*PointMap))) {EPETRA_CHK_ERR(-1);} // Maps not compatible
00731   return(0);
00732 }
00733 //=========================================================================
00734 int Ifpack_CrsRiluk::GenerateXY(bool Trans, 
00735                 const Epetra_MultiVector& Xin, const Epetra_MultiVector& Yin,
00736                 Teuchos::RefCountPtr<Epetra_MultiVector>* Xout, 
00737                 Teuchos::RefCountPtr<Epetra_MultiVector>* Yout) const {
00738 
00739   // Generate an X and Y suitable for performing Solve() and Multiply() methods
00740 
00741   if (Xin.NumVectors()!=Yin.NumVectors()) EPETRA_CHK_ERR(-1); // Return error: X and Y not the same size
00742 
00743   //cout << "Xin = " << Xin << endl;
00744   (*Xout) = Teuchos::rcp( (Epetra_MultiVector *) &Xin, false );
00745   (*Yout) = Teuchos::rcp( (Epetra_MultiVector *) &Yin, false );
00746   if (!IsOverlapped_ && UserMatrixIsCrs_) return(0); // Nothing more to do
00747 
00748   if (UserMatrixIsVbr_) {
00749     if (VbrX_!=Teuchos::null) {
00750       if (VbrX_->NumVectors()!=Xin.NumVectors()) {
00751     VbrX_ = Teuchos::null;
00752     VbrY_ = Teuchos::null;
00753       }
00754     }
00755     if (VbrX_==Teuchos::null) { // Need to allocate space for overlap X and Y
00756       VbrX_ = Teuchos::rcp( new Epetra_MultiVector(View, *U_DomainMap_, (*Xout)->Pointers(), (*Xout)->NumVectors()) );
00757       VbrY_ = Teuchos::rcp( new Epetra_MultiVector(View, *L_RangeMap_, (*Yout)->Pointers(), (*Yout)->NumVectors()) );
00758     }
00759     else {
00760       EPETRA_CHK_ERR(VbrX_->ResetView((*Xout)->Pointers()));
00761       EPETRA_CHK_ERR(VbrY_->ResetView((*Yout)->Pointers()));
00762     }
00763     (*Xout) = VbrX_;
00764     (*Yout) = VbrY_;
00765   }
00766     
00767   if (IsOverlapped_) {
00768     // Make sure the number of vectors in the multivector is the same as before.
00769     if (OverlapX_!=Teuchos::null) {
00770       if (OverlapX_->NumVectors()!=Xin.NumVectors()) {
00771     OverlapX_ = Teuchos::null;
00772     OverlapY_ = Teuchos::null;
00773       }
00774     }
00775     if (OverlapX_==Teuchos::null) { // Need to allocate space for overlap X and Y
00776       OverlapX_ = Teuchos::rcp( new Epetra_MultiVector(U_->RowMatrixColMap(), (*Xout)->NumVectors()) );
00777       OverlapY_ = Teuchos::rcp( new Epetra_MultiVector(L_->RowMatrixRowMap(), (*Yout)->NumVectors()) );
00778     }
00779     if (!Trans) {
00780       EPETRA_CHK_ERR(OverlapX_->Import(*(*Xout),*U_->Importer(), Insert)); // Import X values for solve
00781     }
00782     else {
00783       EPETRA_CHK_ERR(OverlapX_->Import(*(*Xout),*L_->Exporter(), Insert)); // Import X values for solve
00784     }
00785     (*Xout) = OverlapX_;
00786     (*Yout) = OverlapY_; // Set pointers for Xout and Yout to point to overlap space
00787     //cout << "OverlapX_ = " << *OverlapX_ << endl;
00788   }
00789   
00790   return(0);
00791 }
00792 //=============================================================================
00793 // Non-member functions
00794 
00795 ostream& operator << (ostream& os, const Ifpack_CrsRiluk& A)
00796 {
00797 /*  Epetra_fmtflags olda = os.setf(ios::right,ios::adjustfield);
00798   Epetra_fmtflags oldf = os.setf(ios::scientific,ios::floatfield);
00799   int oldp = os.precision(12); */
00800   int LevelFill = A.Graph().LevelFill();
00801   int LevelOverlap = A.Graph().LevelOverlap();
00802   Epetra_CrsMatrix & L = (Epetra_CrsMatrix &) A.L();
00803   Epetra_CrsMatrix & U = (Epetra_CrsMatrix &) A.U();
00804   Epetra_Vector & D = (Epetra_Vector &) A.D();
00805 
00806   os.width(14);
00807   os << endl;
00808   os <<  "     Level of Fill = "; os << LevelFill;
00809   os << endl;
00810   os.width(14);
00811   os <<  "     Level of Overlap = "; os << LevelOverlap;
00812   os << endl;
00813 
00814   os.width(14);
00815   os <<  "     Lower Triangle = ";
00816   os << endl;
00817   os << L; // Let Epetra_CrsMatrix handle the rest.
00818   os << endl;
00819 
00820   os.width(14);
00821   os <<  "     Inverse of Diagonal = ";
00822   os << endl;
00823   os << D; // Let Epetra_Vector handle the rest.
00824   os << endl;
00825 
00826   os.width(14);
00827   os <<  "     Upper Triangle = ";
00828   os << endl;
00829   os << U; // Let Epetra_CrsMatrix handle the rest.
00830   os << endl;
00831  
00832   // Reset os flags
00833 
00834 /*  os.setf(olda,ios::adjustfield);
00835   os.setf(oldf,ios::floatfield);
00836   os.precision(oldp); */
00837 
00838   return os;
00839 }
 All Classes Files Functions Variables Enumerations Friends