//============================================================================== int Ifpack_DropFilter:: ExtractMyRowCopy(int MyRow, int Length, int & NumEntries, double *Values, int * Indices) const { if (Length < NumEntries_[MyRow]) IFPACK_CHK_ERR(-1); int Nnz; IFPACK_CHK_ERR(A_->ExtractMyRowCopy(MyRow,MaxNumEntriesA_,Nnz, &Values_[0],&Indices_[0])); // loop over all nonzero elements of row MyRow, // and drop elements below specified threshold. // Also, add value to zero diagonal int count = 0; for (int i = 0 ; i < Nnz ; ++i) { // if element is above specified tol, add to the // user's defined arrays. Check that we are not // exceeding allocated space. Do not drop any diagonal entry. if ((Indices_[i] == MyRow) || (IFPACK_ABS(Values_[i]) >= DropTol_)) { if (count == Length) IFPACK_CHK_ERR(-1); Values[count] = Values_[i]; Indices[count] = Indices_[i]; count++; } } NumEntries = count; return(0); }
//========================================================================== int Ifpack_ICT::Compute() { if (!IsInitialized()) IFPACK_CHK_ERR(Initialize()); Time_.ResetStartTime(); IsComputed_ = false; NumMyRows_ = A_.NumMyRows(); int Length = A_.MaxNumEntries(); vector<int> RowIndices(Length); vector<double> RowValues(Length); bool distributed = (Comm().NumProc() > 1)?true:false; if (distributed) { SerialComm_ = Teuchos::rcp(new Epetra_SerialComm); SerialMap_ = Teuchos::rcp(new Epetra_Map(NumMyRows_, 0, *SerialComm_)); assert (SerialComm_.get() != 0); assert (SerialMap_.get() != 0); } else SerialMap_ = Teuchos::rcp(const_cast<Epetra_Map*>(&A_.RowMatrixRowMap()), false); int RowNnz; #ifdef IFPACK_FLOPCOUNTERS double flops = 0.0; #endif H_ = Teuchos::rcp(new Epetra_CrsMatrix(Copy,*SerialMap_,0)); if (H_.get() == 0) IFPACK_CHK_ERR(-5); // memory allocation error // get A(0,0) element and insert it (after sqrt) IFPACK_CHK_ERR(A_.ExtractMyRowCopy(0,Length,RowNnz, &RowValues[0],&RowIndices[0])); // skip off-processor elements if (distributed) { int count = 0; for (int i = 0 ;i < RowNnz ; ++i) { if (RowIndices[i] < NumMyRows_){ RowIndices[count] = RowIndices[i]; RowValues[count] = RowValues[i]; ++count; } else continue; } RowNnz = count; } // modify diagonal double diag_val = 0.0; for (int i = 0 ;i < RowNnz ; ++i) { if (RowIndices[i] == 0) { double& v = RowValues[i]; diag_val = AbsoluteThreshold() * EPETRA_SGN(v) + RelativeThreshold() * v; break; } } diag_val = sqrt(diag_val); int diag_idx = 0; EPETRA_CHK_ERR(H_->InsertGlobalValues(0,1,&diag_val, &diag_idx)); // The 10 is just a small constant to limit collisons as the actual keys // we store are the indices and not integers // [0..A_.MaxNumEntries()*LevelofFill()]. Ifpack_HashTable Hash( 10 * A_.MaxNumEntries() * LevelOfFill(), 1); // start factorization for line 1 for (int row_i = 1 ; row_i < NumMyRows_ ; ++row_i) { // get row `row_i' of the matrix IFPACK_CHK_ERR(A_.ExtractMyRowCopy(row_i,Length,RowNnz, &RowValues[0],&RowIndices[0])); // skip off-processor elements if (distributed) { int count = 0; for (int i = 0 ;i < RowNnz ; ++i) { if (RowIndices[i] < NumMyRows_){ RowIndices[count] = RowIndices[i]; RowValues[count] = RowValues[i]; ++count; } else continue; } RowNnz = count; } // number of nonzeros in this row are defined as the nonzeros // of the matrix, plus the level of fill int LOF = (int)(LevelOfFill() * RowNnz); if (LOF == 0) LOF = 1; // convert line `row_i' into hash for fast access Hash.reset(); double h_ii = 0.0; for (int i = 0 ; i < RowNnz ; ++i) { if (RowIndices[i] == row_i) { double& v = RowValues[i]; h_ii = AbsoluteThreshold() * EPETRA_SGN(v) + RelativeThreshold() * v; } else if (RowIndices[i] < row_i) { Hash.set(RowIndices[i], RowValues[i], true); } } // form element (row_i, col_j) // I start from the first row that has a nonzero column // index in row_i. for (int col_j = RowIndices[0] ; col_j < row_i ; ++col_j) { double h_ij = 0.0, h_jj = 0.0; // note: get() returns 0.0 if col_j is not found h_ij = Hash.get(col_j); // get pointers to row `col_j' int* ColIndices; double* ColValues; int ColNnz; H_->ExtractGlobalRowView(col_j, ColNnz, ColValues, ColIndices); for (int k = 0 ; k < ColNnz ; ++k) { int col_k = ColIndices[k]; if (col_k == col_j) h_jj = ColValues[k]; else { double xxx = Hash.get(col_k); if (xxx != 0.0) { h_ij -= ColValues[k] * xxx; #ifdef IFPACK_FLOPCOUNTERS flops += 2.0; #endif } } } h_ij /= h_jj; if (IFPACK_ABS(h_ij) > DropTolerance_) { Hash.set(col_j, h_ij); } #ifdef IFPACK_FLOPCOUNTERS // only approx ComputeFlops_ += 2.0 * flops + 1.0; #endif } int size = Hash.getNumEntries(); vector<double> AbsRow(size); int count = 0; // +1 because I use the extra position for diagonal in insert vector<int> keys(size + 1); vector<double> values(size + 1); Hash.arrayify(&keys[0], &values[0]); for (int i = 0 ; i < size ; ++i) { AbsRow[i] = IFPACK_ABS(values[i]); } count = size; double cutoff = 0.0; if (count > LOF) { nth_element(AbsRow.begin(), AbsRow.begin() + LOF, AbsRow.begin() + count, std::greater<double>()); cutoff = AbsRow[LOF]; } for (int i = 0 ; i < size ; ++i) { h_ii -= values[i] * values[i]; } if (h_ii < 0.0) h_ii = 1e-12;; h_ii = sqrt(h_ii); #ifdef IFPACK_FLOPCOUNTERS // only approx, + 1 == sqrt ComputeFlops_ += 2 * size + 1; #endif double DiscardedElements = 0.0; count = 0; for (int i = 0 ; i < size ; ++i) { if (IFPACK_ABS(values[i]) > cutoff) { values[count] = values[i]; keys[count] = keys[i]; ++count; } else DiscardedElements += values[i]; } if (RelaxValue() != 0.0) { DiscardedElements *= RelaxValue(); h_ii += DiscardedElements; } values[count] = h_ii; keys[count] = row_i; ++count; H_->InsertGlobalValues(row_i, count, &(values[0]), (int*)&(keys[0])); } IFPACK_CHK_ERR(H_->FillComplete()); #if 0 // to check the complete factorization Epetra_Vector LHS(Matrix().RowMatrixRowMap()); Epetra_Vector RHS1(Matrix().RowMatrixRowMap()); Epetra_Vector RHS2(Matrix().RowMatrixRowMap()); Epetra_Vector RHS3(Matrix().RowMatrixRowMap()); LHS.Random(); Matrix().Multiply(false,LHS,RHS1); H_->Multiply(true,LHS,RHS2); H_->Multiply(false,RHS2,RHS3); RHS1.Update(-1.0, RHS3, 1.0); cout << endl; cout << RHS1; #endif int MyNonzeros = H_->NumGlobalNonzeros(); Comm().SumAll(&MyNonzeros, &GlobalNonzeros_, 1); IsComputed_ = true; #ifdef IFPACK_FLOPCOUNTERS double TotalFlops; // sum across all the processors A_.Comm().SumAll(&flops, &TotalFlops, 1); ComputeFlops_ += TotalFlops; #endif ++NumCompute_; ComputeTime_ += Time_.ElapsedTime(); return(0); }
//============================================================================== int Ifpack_Chebyshev::Compute() { if (!IsInitialized()) IFPACK_CHK_ERR(Initialize()); Time_->ResetStartTime(); // reset values IsComputed_ = false; Condest_ = -1.0; if (PolyDegree_ <= 0) IFPACK_CHK_ERR(-2); // at least one application #ifdef HAVE_IFPACK_EPETRAEXT // Check to see if we can run in block mode if(IsRowMatrix_ && InvDiagonal_ == Teuchos::null && UseBlockMode_){ const Epetra_CrsMatrix *CrsMatrix=dynamic_cast<const Epetra_CrsMatrix*>(&*Matrix_); // If we don't have CrsMatrix, we can't use the block preconditioner if(!CrsMatrix) UseBlockMode_=false; else{ int ierr; InvBlockDiagonal_=Teuchos::rcp(new EpetraExt_PointToBlockDiagPermute(*CrsMatrix)); if(InvBlockDiagonal_==Teuchos::null) IFPACK_CHK_ERR(-6); ierr=InvBlockDiagonal_->SetParameters(BlockList_); if(ierr) IFPACK_CHK_ERR(-7); ierr=InvBlockDiagonal_->Compute(); if(ierr) IFPACK_CHK_ERR(-8); } // Automatically Compute Eigenvalues double lambda_max=0; PowerMethod(EigMaxIters_,lambda_max); LambdaMax_=lambda_max; // Test for Exact Preconditioned case if(ABS(LambdaMax_-1) < 1e-6) LambdaMax_=LambdaMin_=1.0; else LambdaMin_=LambdaMax_/EigRatio_; } #endif if (IsRowMatrix_ && InvDiagonal_ == Teuchos::null && !UseBlockMode_) { InvDiagonal_ = Teuchos::rcp( new Epetra_Vector(Matrix().Map()) ); if (InvDiagonal_ == Teuchos::null) IFPACK_CHK_ERR(-5); IFPACK_CHK_ERR(Matrix().ExtractDiagonalCopy(*InvDiagonal_)); // Inverse diagonal elements // Replace zeros with 1.0 for (int i = 0 ; i < NumMyRows_ ; ++i) { double diag = (*InvDiagonal_)[i]; if (IFPACK_ABS(diag) < MinDiagonalValue_) (*InvDiagonal_)[i] = MinDiagonalValue_; else (*InvDiagonal_)[i] = 1.0 / diag; } // Automatically compute maximum eigenvalue estimate of D^{-1}A if user hasn't provided one double lambda_max=0; if (LambdaMax_ == -1) { PowerMethod(Matrix(), *InvDiagonal_, EigMaxIters_, lambda_max); LambdaMax_=lambda_max; // Test for Exact Preconditioned case if (ABS(LambdaMax_-1) < 1e-6) LambdaMax_=LambdaMin_=1.0; else LambdaMin_=LambdaMax_/EigRatio_; } // otherwise the inverse of the diagonal has been given by the user } #ifdef IFPACK_FLOPCOUNTERS ComputeFlops_ += NumMyRows_; #endif ++NumCompute_; ComputeTime_ += Time_->ElapsedTime(); IsComputed_ = true; return(0); }
//============================================================================== int Ifpack_PointRelaxation::Compute() { int ierr = 0; if (!IsInitialized()) IFPACK_CHK_ERR(Initialize()); Time_->ResetStartTime(); // reset values IsComputed_ = false; Condest_ = -1.0; if (NumSweeps_ == 0) ierr = 1; // Warning: no sweeps performed. if (NumSweeps_ < 0) IFPACK_CHK_ERR(-2); // at least one application Diagonal_ = Teuchos::rcp( new Epetra_Vector(Matrix().RowMatrixRowMap()) ); if (Diagonal_ == Teuchos::null) IFPACK_CHK_ERR(-5); IFPACK_CHK_ERR(Matrix().ExtractDiagonalCopy(*Diagonal_)); // check diagonal elements, store the inverses, and verify that // no zeros are around. If an element is zero, then by default // its inverse is zero as well (that is, the row is ignored). for (int i = 0 ; i < NumMyRows_ ; ++i) { double& diag = (*Diagonal_)[i]; if (IFPACK_ABS(diag) < MinDiagonalValue_) diag = MinDiagonalValue_; if (diag != 0.0) diag = 1.0 / diag; } ComputeFlops_ += NumMyRows_; #if 0 // some methods require the inverse of the diagonal, compute it // now and store it in `Diagonal_' if ((PrecType_ == IFPACK_JACOBI) || (PrecType_ == IFPACK_GS)) { Diagonal_->Reciprocal(*Diagonal_); // update flops ComputeFlops_ += NumMyRows_; } #endif // We need to import data from external processors. Here I create an // Epetra_Import object because I cannot assume that Matrix_ has one. // This is a bit of waste of resources (but the code is more robust). // Note that I am doing some strange stuff to set the components of Y // from Y2 (to save some time). // if (IsParallel_ && ((PrecType_ == IFPACK_GS) || (PrecType_ == IFPACK_SGS))) { Importer_ = Teuchos::rcp( new Epetra_Import(Matrix().RowMatrixColMap(), Matrix().RowMatrixRowMap()) ); if (Importer_ == Teuchos::null) IFPACK_CHK_ERR(-5); } ++NumCompute_; ComputeTime_ += Time_->ElapsedTime(); IsComputed_ = true; IFPACK_CHK_ERR(ierr); return(0); }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI MPI_Init(&argc,&argv); Epetra_MpiComm Comm( MPI_COMM_WORLD ); #else Epetra_SerialComm Comm; #endif if (Comm.NumProc() == 1) { #ifdef HAVE_MPI MPI_Finalize(); #endif cout << "Test `TestOverlappingRowMatrix.exe' passed!" << endl; exit(EXIT_SUCCESS); } Teuchos::ParameterList GaleriList; int nx = 100; GaleriList.set("n", nx * nx); GaleriList.set("nx", nx); GaleriList.set("ny", nx); Teuchos::RefCountPtr<Epetra_Map> Map = Teuchos::rcp( Galeri::CreateMap64("Linear", Comm, GaleriList) ); Teuchos::RefCountPtr<Epetra_CrsMatrix> A = Teuchos::rcp( Galeri::CreateCrsMatrix("Laplace2D", &*Map, GaleriList) ); int OverlapLevel = 5; Epetra_Time Time(Comm); // ======================================== // // Build the overlapping matrix using class // // Ifpack_OverlappingRowMatrix. // // ======================================== // Time.ResetStartTime(); Ifpack_OverlappingRowMatrix B(A,OverlapLevel); if (Comm.MyPID() == 0) cout << "Time to create B = " << Time.ElapsedTime() << endl; long long NumGlobalRowsB = B.NumGlobalRows64(); long long NumGlobalNonzerosB = B.NumGlobalNonzeros64(); Epetra_Vector X(A->RowMatrixRowMap()); Epetra_Vector Y(A->RowMatrixRowMap()); for (int i = 0 ; i < A->NumMyRows() ; ++i) X[i] = 1.0* A->RowMatrixRowMap().GID64(i); Y.PutScalar(0.0); Epetra_Vector ExtX_B(B.RowMatrixRowMap()); Epetra_Vector ExtY_B(B.RowMatrixRowMap()); ExtY_B.PutScalar(0.0); IFPACK_CHK_ERR(B.ImportMultiVector(X,ExtX_B)); IFPACK_CHK_ERR(B.Multiply(false,ExtX_B,ExtY_B)); IFPACK_CHK_ERR(B.ExportMultiVector(ExtY_B,Y,Add)); double Norm_B; Y.Norm2(&Norm_B); if (Comm.MyPID() == 0) cout << "Norm of Y using B = " << Norm_B << endl; // ================================================== // //Build the overlapping matrix as an Epetra_CrsMatrix // // ================================================== // Time.ResetStartTime(); Epetra_CrsMatrix& C = *(Ifpack_CreateOverlappingCrsMatrix(&*A,OverlapLevel)); if (Comm.MyPID() == 0) cout << "Time to create C = " << Time.ElapsedTime() << endl; // simple checks on global quantities long long NumGlobalRowsC = C.NumGlobalRows64(); long long NumGlobalNonzerosC = C.NumGlobalNonzeros64(); assert (NumGlobalRowsB == NumGlobalRowsC); assert (NumGlobalNonzerosB == NumGlobalNonzerosC); Epetra_Vector ExtX_C(C.RowMatrixRowMap()); Epetra_Vector ExtY_C(C.RowMatrixRowMap()); ExtY_C.PutScalar(0.0); Y.PutScalar(0.0); IFPACK_CHK_ERR(C.Multiply(false,X,Y)); double Norm_C; Y.Norm2(&Norm_C); if (Comm.MyPID() == 0) cout << "Norm of Y using C = " << Norm_C << endl; if (IFPACK_ABS(Norm_B - Norm_C) > 1e-5) IFPACK_CHK_ERR(-1); // ======================= // // now localize the matrix // // ======================= // Ifpack_LocalFilter D(Teuchos::rcp(&B, false)); #ifdef HAVE_MPI MPI_Finalize() ; #endif if (Comm.MyPID() == 0) cout << "Test `TestOverlappingRowMatrix.exe' passed!" << endl; return(EXIT_SUCCESS); }