IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_NodeFilter.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 #ifdef IFPACK_NODE_AWARE_CODE
00044 
00045 #include "Ifpack_ConfigDefs.h"
00046 
00047 #include "Epetra_MultiVector.h"
00048 #include "Epetra_Vector.h"
00049 #include "Epetra_IntVector.h"
00050 #include "Epetra_RowMatrix.h"
00051 #include "Epetra_Map.h"
00052 #include "Epetra_BlockMap.h"
00053 #include "Ifpack_NodeFilter.h"
00054 #include "Ifpack_OverlappingRowMatrix.h"
00055 #include "Epetra_Import.h"
00056 #include "Epetra_Export.h"
00057 #include "Epetra_CrsMatrix.h"
00058 #include "Epetra_BLAS_wrappers.h"
00059 
00060 using namespace Teuchos;
00061 
00062 #define OLD_AND_BUSTED
00063 
00064 //==============================================================================
00065 Ifpack_NodeFilter::Ifpack_NodeFilter(const RefCountPtr<const Epetra_RowMatrix>& Matrix,int nodeID) :
00066   Matrix_(Matrix),
00067   NumMyRows_(0),
00068   NumMyNonzeros_(0),
00069   NumGlobalRows_(0),
00070   MaxNumEntries_(0),
00071   MaxNumEntriesA_(0)
00072 {
00073   sprintf(Label_,"%s","Ifpack_NodeFilter");
00074 
00075   //ImportVector_=null;
00076   //ExportVector_=null;
00077   ImportVector_=0;
00078   ExportVector_=0;
00079 
00080   ovA_ = dynamic_cast<const Ifpack_OverlappingRowMatrix*>(&*Matrix_);
00081   //assert(ovA_ != 0);
00082 
00083   if (ovA_) {
00084     Acrs_=dynamic_cast<const Epetra_CrsMatrix*>(&ovA_->A());
00085     NumMyRowsA_ = ovA_->A().NumMyRows();
00086     NumMyRowsB_ = ovA_->B().NumMyRows();
00087   } else {
00088     NumMyRowsA_ = Matrix->NumMyRows();
00089     NumMyRowsB_ = 0;
00090   }
00091   
00092 #ifdef HAVE_MPI
00093   const Epetra_MpiComm *pComm = dynamic_cast<const Epetra_MpiComm*>( &(Matrix->Comm()) );
00094   assert(pComm != NULL);
00095   MPI_Comm_split(pComm->Comm(),nodeID,pComm->MyPID(),&nodeMPIComm_);
00096   SubComm_ = rcp( new Epetra_MpiComm(nodeMPIComm_) );
00097 #else
00098   SubComm_ = rcp( new Epetra_SerialComm );
00099 #endif
00100 
00101   NumMyRows_ = Matrix->NumMyRows();
00102   SubComm_->SumAll(&NumMyRows_,&NumGlobalRows_,1);
00103   NumMyCols_ = Matrix->NumMyCols();
00104 
00105   // build row map, based on the local communicator
00106   try {
00107     const Epetra_Map &globRowMap = Matrix->RowMatrixRowMap();
00108     int *myGlobalElts =  globRowMap.MyGlobalElements();
00109     int numMyElts = globRowMap.NumMyElements();
00110     Map_ = rcp( new Epetra_Map(-1,numMyElts,myGlobalElts,globRowMap.IndexBase(),*SubComm_) );
00111   }
00112   catch(...) {
00113     printf("** * Ifpack_NodeFilter ctor: problem creating row map * **\n\n");
00114   }
00115 
00116 
00117   // build the column map, but don't use a copy constructor, b/c local communicator SubComm_ is
00118   // different from that of Matrix.
00119   try {
00120     const Epetra_Map &globColMap = Matrix->RowMatrixColMap();
00121     int *myGlobalElts =  globColMap.MyGlobalElements();
00122     int numMyElts = globColMap.NumMyElements();
00123     colMap_ = rcp( new Epetra_Map(-1,numMyElts,myGlobalElts,globColMap.IndexBase(),*SubComm_) );
00124   }
00125   catch(...) {
00126     printf("** * Ifpack_NodeFilter ctor: problem creating col map * **\n\n");
00127   }
00128 
00129   // NumEntries_ will contain the actual number of nonzeros
00130   // for each localized row (that is, without external nodes,
00131   // and always with the diagonal entry)
00132   NumEntries_.resize(NumMyRows_);
00133 
00134   // want to store the diagonal vector. FIXME: am I really useful?
00135   Diagonal_ = rcp( new Epetra_Vector(*Map_) );
00136   if (Diagonal_ == Teuchos::null) IFPACK_CHK_ERRV(-5);
00137 
00138   // store this for future access to ExtractMyRowCopy().
00139   // This is the # of nonzeros in the non-local matrix
00140   MaxNumEntriesA_ = Matrix->MaxNumEntries();
00141   // tentative value for MaxNumEntries. This is the number of
00142   // nonzeros in the local matrix
00143   MaxNumEntries_ = Matrix->MaxNumEntries();
00144 
00145   // ExtractMyRowCopy() will use these vectors
00146   Indices_.resize(MaxNumEntries_);
00147   Values_.resize(MaxNumEntries_);
00148 
00149   // now compute:
00150   // - the number of nonzero per row
00151   // - the total number of nonzeros
00152   // - the diagonal entries
00153 
00154 
00155   Ac_LIDMap_ = 0;
00156   Bc_LIDMap_ = 0;
00157   Ar_LIDMap_ = 0;
00158   Br_LIDMap_ = 0;
00159   tempX_ = 0;
00160   tempY_ = 0;
00161   // CMS: [A|B]-Local to Overlap-Local Column Indices
00162   if(ovA_){
00163     Ac_LIDMap_=new int[ovA_->A().NumMyCols()+1];
00164     for(int i=0;i<ovA_->A().NumMyCols();i++) Ac_LIDMap_[i]=colMap_->LID(ovA_->A().RowMatrixColMap().GID(i));    
00165     Bc_LIDMap_=new int[ovA_->B().NumMyCols()+1];
00166     for(int i=0;i<ovA_->B().NumMyCols();i++) Bc_LIDMap_[i]=colMap_->LID(ovA_->B().RowMatrixColMap().GID(i));
00167 
00168     Ar_LIDMap_=new int[ovA_->A().NumMyRows()+1];
00169     for(int i=0;i<ovA_->A().NumMyRows();i++) Ar_LIDMap_[i]=Map_->LID(ovA_->A().RowMatrixRowMap().GID(i));    
00170     Br_LIDMap_=new int[ovA_->B().NumMyRows()+1];
00171     for(int i=0;i<ovA_->B().NumMyRows();i++) Br_LIDMap_[i]=Map_->LID(ovA_->B().RowMatrixRowMap().GID(i));
00172 
00173 
00174 #ifndef OLD_AND_BUSTED
00175     NumMyColsA_=ovA_->A().NumMyCols();
00176     tempX_=new double[NumMyColsA_];
00177     tempY_=new double[NumMyRowsA_];     
00178 #else
00179     tempX_=0;
00180     tempY_=0;
00181 #endif
00182   }
00183   // end CMS
00184 
00185 
00186   // compute nonzeros (total and per-row), and store the
00187   // diagonal entries (already modified)
00188   int ActualMaxNumEntries = 0;
00189 
00190   for (int i = 0 ; i < NumMyRows_ ; ++i) {
00191     
00192     NumEntries_[i] = 0;
00193     int Nnz, NewNnz = 0;
00194     IFPACK_CHK_ERRV(ExtractMyRowCopy(i,MaxNumEntries_,Nnz,&Values_[0],&Indices_[0]));
00195 
00196     for (int j = 0 ; j < Nnz ; ++j) {
00197       NewNnz++;
00198       if (Indices_[j] == i) (*Diagonal_)[i] = Values_[j];
00199     }
00200 
00201     if (NewNnz > ActualMaxNumEntries)
00202       ActualMaxNumEntries = NewNnz;
00203 
00204     NumMyNonzeros_ += NewNnz;
00205     NumEntries_[i] = NewNnz;
00206 
00207   }
00208 
00209   SubComm_->SumAll(&NumMyNonzeros_,&NumGlobalNonzeros_,1);
00210   MaxNumEntries_ = ActualMaxNumEntries;
00211 
00212   int gpid = Matrix->Comm().MyPID();
00213   Exporter_ = null;
00214   Importer_ = null;
00215   // Check if non-trivial import/export operators
00216   if (!(RowMatrixRowMap().SameAs(OperatorRangeMap()))) {
00217     try{Exporter_ = rcp(new Epetra_Export(RowMatrixRowMap(), OperatorRangeMap()));}
00218     catch(...) {
00219       printf("** * gpid %d: Ifpack_NodeFilter ctor: problem creating Exporter_ * **\n\n",gpid);
00220     }
00221   }
00222   if (!(*colMap_).SameAs(*Map_)) {
00223     //TODO change this to RCP
00224     try{Importer_ = rcp(new Epetra_Import(*colMap_, *Map_));}
00225     catch(...) {
00226       printf("** * gpid %d: Ifpack_NodeFilter ctor: problem creating Importer_ * **\n\n",gpid);
00227     }
00228   }
00229 
00230 } //Ifpack_NodeFilter() ctor
00231 
00232 //==============================================================================
00233 int Ifpack_NodeFilter::
00234 ExtractMyRowCopy(int MyRow, int Length, int & NumEntries, 
00235          double *Values, int * Indices) const
00236 {
00237   if ((MyRow < 0) || (MyRow >= NumMyRows_)) {
00238     IFPACK_CHK_ERR(-1); // range not valid
00239   }
00240 
00241   if (Length < NumEntries_[MyRow])
00242     assert(1==0);
00243     //return(-1);
00244 
00245   //TODO  will we have problems in the original use case?
00246   // always extract using the object Values_ and Indices_.
00247   // This is because I need more space than that given by
00248   // the user (for the external nodes)
00249 
00250   int ierr;
00251   if (ovA_) {
00252     int LocRow=ovA_->A().RowMatrixRowMap().LID(Map_->GID(MyRow));      
00253     if (LocRow != -1) { 
00254       ierr=ovA_->A().ExtractMyRowCopy(LocRow,Length,NumEntries,Values,Indices);
00255       for(int j=0;j<NumEntries;j++)
00256     Indices[j]=Ac_LIDMap_[Indices[j]];
00257       
00258     }
00259     else {
00260       LocRow=ovA_->B().RowMatrixRowMap().LID(Map_->GID(MyRow));      
00261       ierr=ovA_->B().ExtractMyRowCopy(LocRow,Length,NumEntries,Values,Indices);
00262       for(int j=0;j<NumEntries;j++)
00263     Indices[j]=Bc_LIDMap_[Indices[j]];
00264     }
00265   } else {
00266     int Nnz;
00267     ierr = Matrix_->ExtractMyRowCopy(MyRow,MaxNumEntriesA_,Nnz, &Values_[0],&Indices_[0]);
00268     IFPACK_CHK_ERR(ierr);
00269 
00270     NumEntries = 0;
00271     for (int j = 0 ; j < Nnz ; ++j) {
00272       // only local indices
00273       if (Indices_[j] < NumMyRows_ ) {
00274         Indices[NumEntries] = Indices_[j];
00275         Values[NumEntries] = Values_[j];
00276         ++NumEntries;
00277       }
00278     }
00279   }
00280     
00281   return(ierr);
00282 
00283 }
00284 
00285 //==============================================================================
00286 int Ifpack_NodeFilter::ExtractDiagonalCopy(Epetra_Vector & Diagonal) const
00287 {
00288   if (!Diagonal.Map().SameAs(*Map_))
00289     IFPACK_CHK_ERR(-1);
00290   Diagonal = *Diagonal_;
00291   return(0);
00292 }
00293 
00294 //==============================================================================
00295 /*
00296 //old Apply (no communication)
00297 int Ifpack_NodeFilter::Apply(const Epetra_MultiVector& X,
00298       Epetra_MultiVector& Y) const 
00299 {
00300 
00301   // skip expensive checks, I suppose input data are ok
00302 
00303   Y.PutScalar(0.0);
00304   int NumVectors = Y.NumVectors();
00305 
00306   double** X_ptr;
00307   double** Y_ptr;
00308   X.ExtractView(&X_ptr);
00309   Y.ExtractView(&Y_ptr);
00310 
00311   for (int i = 0 ; i < NumRows_ ; ++i) {
00312     
00313     int Nnz;
00314     int ierr = Matrix_->ExtractMyRowCopy(i,MaxNumEntriesA_,Nnz,&Values_[0],
00315                                          &Indices_[0]);
00316     IFPACK_CHK_ERR(ierr);
00317 
00318     for (int j = 0 ; j < Nnz ; ++j) {
00319       if (Indices_[j] < NumRows_ ) {
00320     for (int k = 0 ; k < NumVectors ; ++k)
00321       Y_ptr[k][i] += Values_[j] * X_ptr[k][Indices_[j]];
00322       }
00323     }
00324   }
00325 
00326   return(0);
00327 }
00328 */
00329 int Ifpack_NodeFilter::Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const {
00330   //
00331   // This function forms the product Y = A * X.
00332   //
00333 
00334   int NumEntries;
00335 
00336   int NumVectors = X.NumVectors();
00337   if (NumVectors!=Y.NumVectors()) {
00338     EPETRA_CHK_ERR(-1); // Need same number of vectors in each MV
00339   }
00340 
00341   // Make sure Import and Export Vectors are compatible
00342   UpdateImportVector(NumVectors);
00343   UpdateExportVector(NumVectors);
00344 
00345   double ** Xp = (double**) X.Pointers();
00346   double ** Yp = (double**) Y.Pointers();
00347 
00348 
00349   // If we have a non-trivial importer, we must import elements that are permuted or are on other processors
00350   if (Importer()!=0) {
00351     EPETRA_CHK_ERR(ImportVector_->Import(X, *Importer(), Insert));
00352     Xp = (double**)ImportVector_->Pointers();
00353   }
00354 
00355   // If we have a non-trivial exporter, we must export elements that are permuted or belong to other processors
00356   if (Exporter()!=0) {
00357     Yp = (double**)ExportVector_->Pointers();
00358   }
00359 
00360   // Do actual computation
00361   assert(ovA_!=0);
00362   int *MyRows;
00363   double *MyValues;
00364   int *MyIndices;
00365 
00366   if(Acrs_){
00367     // A rows - CrsMatrix Case
00368     IFPACK_CHK_ERR(Acrs_->ExtractCrsDataPointers(MyRows,MyIndices,MyValues));
00369     //special case NumVectors==1
00370     if (NumVectors==1) {
00371 #ifdef OLD_AND_BUSTED
00372 
00373       for(int i=0;i<NumMyRowsA_;i++) {
00374         int LocRow=Ar_LIDMap_[i];
00375         double sum = 0.0;
00376         for(int j = MyRows[i]; j < MyRows[i+1]; j++)
00377           sum += MyValues[j]*Xp[0][Ac_LIDMap_[MyIndices[j]]];          
00378         Yp[0][LocRow] = sum;
00379       }
00380 #else      
00381       int izero=0;
00382       for(int i=0;i<NumMyColsA_;i++) tempX_[i]=Xp[0][Ac_LIDMap_[i]];
00383       EPETRA_DCRSMV_F77(&izero,&NumMyRowsA_,&NumMyRowsA_,MyValues,MyIndices,MyRows,tempX_,tempY_);
00384 
00385       /*      for(int i=0;i<NumMyRowsA_;i++) {
00386         double sum = 0.0;
00387         for(int j = MyRows[i]; j < MyRows[i+1]; j++)
00388           sum += MyValues[j]*tempX_[MyIndices[j]];
00389         tempY_[i] = sum;
00390         }*/
00391       
00392       for(int i=0;i<NumMyRowsA_;i++) Yp[0][Ar_LIDMap_[i]]=tempY_[i];    
00393 #endif
00394 
00395     }
00396     else {
00397       for(int i=0;i<NumMyRowsA_;i++) {
00398         int LocRow=Ar_LIDMap_[i];
00399         for (int k=0; k<NumVectors; k++) {
00400           double sum = 0.0;
00401           for(int j = MyRows[i]; j < MyRows[i+1]; j++)
00402             sum += MyValues[j]*Xp[k][Ac_LIDMap_[MyIndices[j]]];          
00403           Yp[k][LocRow] = sum;
00404         }
00405       }
00406     }
00407   }
00408   else{
00409     // A rows - RowMatrix Case
00410     MyValues=&Values_[0];
00411     MyIndices=&Indices_[0];
00412     for(int i=0;i<NumMyRowsA_;i++) {
00413       ovA_->A().ExtractMyRowCopy(i,MaxNumEntries_,NumEntries,MyValues,MyIndices);
00414       int LocRow=Ar_LIDMap_[i];
00415       for (int k=0; k<NumVectors; k++) {
00416         double sum = 0.0;
00417         for(int j = 0; j < NumEntries; j++)
00418         sum += MyValues[j]*Xp[k][Ac_LIDMap_[MyIndices[j]]];          
00419         Yp[k][LocRow] = sum;
00420       }
00421     }
00422   }
00423 
00424   // B rows, always CrsMatrix
00425   IFPACK_CHK_ERR(ovA_->B().ExtractCrsDataPointers(MyRows,MyIndices,MyValues));
00426   //special case NumVectors==1
00427   if (NumVectors==1) {
00428     for(int i=0;i<NumMyRowsB_;i++) {
00429       int LocRow=Br_LIDMap_[i];
00430       double sum = 0.0;
00431       for(int j = MyRows[i]; j < MyRows[i+1]; j++)
00432         sum += MyValues[j]*Xp[0][Bc_LIDMap_[MyIndices[j]]];          
00433       Yp[0][LocRow] = sum;
00434     }
00435   } else {
00436     for(int i=0;i<NumMyRowsB_;i++) {
00437       int LocRow=Br_LIDMap_[i];
00438       for (int k=0; k<NumVectors; k++) { //FIXME optimization, check for NumVectors=1
00439         double sum = 0.0;
00440         for(int j = MyRows[i]; j < MyRows[i+1]; j++)
00441           sum += MyValues[j]*Xp[k][Bc_LIDMap_[MyIndices[j]]];          
00442         Yp[k][LocRow] = sum;
00443       }
00444     }
00445   }
00446 
00447   if (Exporter()!=0) {
00448     Y.PutScalar(0.0);  // Make sure target is zero
00449     Y.Export(*ExportVector_, *Exporter(), Add); // Fill Y with Values from export vector
00450   }
00451   // Handle case of rangemap being a local replicated map
00452   if (!OperatorRangeMap().DistributedGlobal() && Comm().NumProc()>1) EPETRA_CHK_ERR(Y.Reduce());
00453 
00454   return(0);
00455 } //Apply
00456 
00457 //==============================================================================
00458 
00459 void Ifpack_NodeFilter::UpdateImportVector(int NumVectors) const {
00460   if(Importer() != 0) {
00461     if(ImportVector_ != 0) {
00462       if(ImportVector_->NumVectors() != NumVectors) {
00463      delete ImportVector_;
00464      ImportVector_= 0;
00465       }
00466     }
00467     if(ImportVector_ == 0)
00468       ImportVector_ = new Epetra_MultiVector(Importer_->TargetMap(),NumVectors); // Create Import vector if needed
00469   }
00470   return;
00471 /*
00472   if(ImportVector_ == null || ImportVector_->NumVectors() != NumVectors)
00473     ImportVector_ = rcp(new Epetra_MultiVector(Importer_->TargetMap(),NumVectors));
00474 */
00475 }
00476 
00477 //=======================================================================================================
00478 
00479 void Ifpack_NodeFilter::UpdateExportVector(int NumVectors) const {
00480   if(Exporter() != 0) {
00481     if(ExportVector_ != 0) {
00482       if(ExportVector_->NumVectors() != NumVectors) {
00483      delete ExportVector_;
00484      ExportVector_= 0;
00485       }
00486     }
00487     if(ExportVector_ == 0)
00488       ExportVector_ = new Epetra_MultiVector(Exporter_->SourceMap(),NumVectors); // Create Export vector if needed
00489   }
00490   return;
00491 /*
00492   if(ExportVector_ == null || ExportVector_->NumVectors() != NumVectors)
00493     ExportVector_ = rcp(new Epetra_MultiVector(Exporter_->SourceMap(),NumVectors));
00494 */
00495 }
00496 
00497 //=======================================================================================================
00498 int Ifpack_NodeFilter::ApplyInverse(const Epetra_MultiVector& X,
00499          Epetra_MultiVector& Y) const
00500 {
00501   IFPACK_CHK_ERR(-1); // not implemented
00502 }
00503 
00504 //==============================================================================
00505 const Epetra_BlockMap& Ifpack_NodeFilter::Map() const
00506 {
00507   return(*Map_);
00508 
00509 }
00510 
00511 #endif //ifdef IFPACK_NODE_AWARE_CODE
 All Classes Files Functions Variables Enumerations Friends