//============================================================================= // This function finds Y such that LDU Y = X or U(trans) D L(trans) Y = X for multiple RHS int Ifpack_SPARSKIT::ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-3); // compute preconditioner first if (X.NumVectors() != Y.NumVectors()) IFPACK_CHK_ERR(-2); // Return error: X and Y not the same size int n = Matrix().NumMyRows(); for (int i = 0 ; i < X.NumVectors() ; ++i) F77_LUSOL(&n, (double*)X(i)->Values(), Y(i)->Values(), (double*)&alu_[0], (int*)&jlu_[0], (int*)&ju_[0]); // still need to fix support for permutation if (Type_ == "ILUTP" || Type_ == "ILUDP") { vector<double> tmp(n); for (int j = 0 ; j < n ; ++j) tmp[iperm_[j]] = Y[0][j]; for (int j = 0 ; j < n ; ++j) Y[0][j] = tmp[j]; } ++NumApplyInverse_; return(0); }
//============================================================================== int Ifpack2_Amesos:: ApplyInverse(const Tpetra_MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node>& X, Tpetra_MultiVector<Scalar,LocalOrdinal,GlobalOrdinal,Node>& Y) const { if (IsComputed() == false) IFPACK2_CHK_ERR(-1); if (X.NumVectors() != Y.NumVectors()) IFPACK2_CHK_ERR(-1); // wrong input Time_->ResetStartTime(); // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy Teuchos::RCP<const Tpetra_MultiVector> Xcopy; if (X.Pointers()[0] == Y.Pointers()[0]) Xcopy = Teuchos::rcp( new Tpetra_MultiVector(X) ); else Xcopy = Teuchos::rcp( &X, false ); Problem_->SetLHS(&Y); Problem_->SetRHS((Tpetra_MultiVector*)Xcopy.get()); IFPACK2_CHK_ERR(Solver_->Solve()); ++NumApplyInverse_; ApplyInverseTime_ += Time_->ElapsedTime(); return(0); }
//============================================================================== int Ifpack_ML:: ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (IsComputed() == false) IFPACK_CHK_ERR(-1); int numVectors = X.NumVectors(); if (numVectors != Y.NumVectors()) IFPACK_CHK_ERR(-1); // wrong input Time_->ResetStartTime(); // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy Teuchos::RefCountPtr<const Epetra_MultiVector> Xcopy; if (X.Pointers()[0] == Y.Pointers()[0]) Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) ); else Xcopy = Teuchos::rcp( &X, false ); for (int i=0; i<numVectors; i++) { IFPACK_CHK_ERR(MLPrec_->ApplyInverse(*Xcopy,Y)); } ++NumApplyInverse_; ApplyInverseTime_ += Time_->ElapsedTime(); return(0); }
int Ifpack2_SparseContainer<T>::ApplyInverse() { if (!IsComputed()) IFPACK2_CHK_ERR(-1); IFPACK2_CHK_ERR(Inverse_->ApplyInverse(*RHS_, *LHS_)); return(0); }
int Ifpack2_SparseContainer<T>::Apply() { if (IsComputed() == false) { IFPACK2_CHK_ERR(-3); // not yet computed } IFPACK2_CHK_ERR(Matrix_->Apply(*RHS_, *LHS_)); ApplyFlops_ += 2 * Matrix_->NumGlobalNonzeros(); return(0); }
//============================================================================== int Ifpack2_AMDReordering::InvReorder(const int i) const { #ifdef IFPACK2_ABC if (!IsComputed()) IFPACK2_CHK_ERR(-1); if ((i < 0) || (i >= NumMyRows_)) IFPACK2_CHK_ERR(-1); #endif return(InvReorder_[i]); }
//============================================================================= double Ifpack_SPARSKIT::Condest(const Ifpack_CondestType CT, const int MaxIters, const double Tol, Epetra_RowMatrix* Matrix) { if (!IsComputed()) // cannot compute right now return(-1.0); if (Condest_ == -1.0) Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix); return(Condest_); }
//============================================================================= double Ifpack_ICT::Condest(const Ifpack_CondestType CT, const int MaxIters, const double Tol, Epetra_RowMatrix* Matrix_in) { if (!IsComputed()) // cannot compute right now return(-1.0); // NOTE: this is computing the *local* condest if (Condest_ == -1.0) Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in); return(Condest_); }
//============================================================================== double Ifpack2_Amesos::Condest(const Ifpack2_CondestType CT, const int MaxIters, const double Tol, Tpetra_RowMatrix* Matrix_in) { if (!IsComputed()) // cannot compute right now return(-1.0); if (Condest_ == -1.0) Condest_ = Ifpack2_Condest(*this, CT, MaxIters, Tol, Matrix_in); return(Condest_); }
//============================================================================== double Ifpack_Chebyshev:: Condest(const Ifpack_CondestType CT, const int MaxIters, const double Tol, Epetra_RowMatrix* Matrix_in) { if (!IsComputed()) // cannot compute right now return(-1.0); // always computes it. Call Condest() with no parameters to get // the previous estimate. Condest_ = Ifpack_Condest(*this, CT, MaxIters, Tol, Matrix_in); return(Condest_); }
//============================================================================== ostream& Ifpack2_AMDReordering::Print(std::ostream& os) const { os << "*** Ifpack2_AMDReordering" << endl << endl; if (!IsComputed()) os << "*** Reordering not yet computed." << endl; os << "*** Number of local rows = " << NumMyRows_ << endl; os << endl; os << "Local Row\tReorder[i]\tInvReorder[i]" << endl; for (int i = 0 ; i < NumMyRows_ ; ++i) { os << '\t' << i << "\t\t" << Reorder_[i] << "\t\t" << InvReorder_[i] << endl; } return(os); }
ostream& Ifpack2_SparseContainer<T>::Print(ostream & os) const { os << "================================================================================" << endl; os << "Ifpack2_SparseContainer" << endl; os << "Number of rows = " << NumRows() << endl; os << "Number of vectors = " << NumVectors() << endl; os << "IsInitialized() = " << IsInitialized() << endl; os << "IsComputed() = " << IsComputed() << endl; os << "Flops in Initialize() = " << InitializeFlops() << endl; os << "Flops in Compute() = " << ComputeFlops() << endl; os << "Flops in ApplyInverse() = " << ApplyInverseFlops() << endl; os << "================================================================================" << endl; os << endl; return(os); }
//============================================================================== int Ifpack_Chebyshev:: Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (IsComputed() == false) IFPACK_CHK_ERR(-3); if (X.NumVectors() != Y.NumVectors()) IFPACK_CHK_ERR(-2); if (IsRowMatrix_) { IFPACK_CHK_ERR(Matrix_->Multiply(UseTranspose(),X,Y)); } else { IFPACK_CHK_ERR(Operator_->Apply(X,Y)); } return(0); }
//============================================================================== Ifpack2_AMDReordering& Ifpack2_AMDReordering:: operator=(const Ifpack2_AMDReordering& RHS) { if (this == &RHS) { return (*this); } NumMyRows_ = RHS.NumMyRows(); // set number of local rows IsComputed_ = RHS.IsComputed(); // resize vectors, and copy values from RHS Reorder_.resize(NumMyRows()); InvReorder_.resize(NumMyRows()); if (IsComputed()) { for (int i = 0 ; i < NumMyRows_ ; ++i) { Reorder_[i] = RHS.Reorder(i); InvReorder_[i] = RHS.InvReorder(i); } } return (*this); }
//============================================================================== // Note that Ifpack_PointRelaxation and Jacobi is much faster than // Ifpack_AdditiveSchwarz<Ifpack_PointRelaxation> (because of the // way the matrix-vector produce is performed). // // Another ML-related observation is that the starting solution (in Y) // is NOT supposed to be zero. This may slow down the application of just // one sweep of Jacobi. // int Ifpack_PointRelaxation:: ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-3); if (X.NumVectors() != Y.NumVectors()) IFPACK_CHK_ERR(-2); Time_->ResetStartTime(); // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy Teuchos::RefCountPtr< const Epetra_MultiVector > Xcopy; if (X.Pointers()[0] == Y.Pointers()[0]) Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) ); else Xcopy = Teuchos::rcp( &X, false ); if (ZeroStartingSolution_) Y.PutScalar(0.0); // Flops are updated in each of the following. switch (PrecType_) { case IFPACK_JACOBI: IFPACK_CHK_ERR(ApplyInverseJacobi(*Xcopy,Y)); break; case IFPACK_GS: IFPACK_CHK_ERR(ApplyInverseGS(*Xcopy,Y)); break; case IFPACK_SGS: IFPACK_CHK_ERR(ApplyInverseSGS(*Xcopy,Y)); break; default: IFPACK_CHK_ERR(-1); // something wrong } ++NumApplyInverse_; ApplyInverseTime_ += Time_->ElapsedTime(); return(0); }
//============================================================================== int Ifpack_Krylov:: ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-3); if (Iterations_ == 0) return 0; int nVec = X.NumVectors(); if (nVec != Y.NumVectors()) IFPACK_CHK_ERR(-2); Time_->ResetStartTime(); // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy Teuchos::RCP<Epetra_MultiVector> Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) ); if(ZeroStartingSolution_==true) { Y.PutScalar(0.0); } #ifdef HAVE_IFPACK_AZTECOO AztecSolver_ -> SetLHS(&Y); AztecSolver_ -> SetRHS(&*Xcopy); AztecSolver_ -> Iterate(Iterations_,Tolerance_); #else cout << "You need to configure IFPACK with support for AztecOO" << endl; cout << "to use this preconditioner. This may require --enable-aztecoo" << endl; cout << "in your configure script." << endl; IFPACK_CHK_ERR(-1); #endif // Flops are updated in each of the following. ++NumApplyInverse_; ApplyInverseTime_ += Time_->ElapsedTime(); return(0); }
//============================================================================= int Ifpack_ICT::ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-3); // compute preconditioner first if (X.NumVectors() != Y.NumVectors()) IFPACK_CHK_ERR(-2); // Return error: X and Y not the same size Time_.ResetStartTime(); // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy Teuchos::RefCountPtr<const Epetra_MultiVector> Xcopy; if (X.Pointers()[0] == Y.Pointers()[0]) Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) ); else Xcopy = Teuchos::rcp( &X, false ); // NOTE: H_ is based on SerialMap_, while Xcopy is based // on A.Map()... which are in general different. However, Solve() // does not seem to care... which is fine with me. // EPETRA_CHK_ERR(H_->Solve(false,false,false,*Xcopy,Y)); EPETRA_CHK_ERR(H_->Solve(false,true,false,Y,Y)); #ifdef IFPACK_FLOPCOUNTERS // these are global flop count ApplyInverseFlops_ += 4.0 * GlobalNonzeros_; #endif ++NumApplyInverse_; ApplyInverseTime_ += Time_.ElapsedTime(); return(0); }
//============================================================================== int Ifpack_Chebyshev:: ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-3); if (PolyDegree_ == 0) return 0; int nVec = X.NumVectors(); int len = X.MyLength(); if (nVec != Y.NumVectors()) IFPACK_CHK_ERR(-2); Time_->ResetStartTime(); // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy Teuchos::RefCountPtr<const Epetra_MultiVector> Xcopy; if (X.Pointers()[0] == Y.Pointers()[0]) Xcopy = Teuchos::rcp( new Epetra_MultiVector(X) ); else Xcopy = Teuchos::rcp( &X, false ); double **xPtr = 0, **yPtr = 0; Xcopy->ExtractView(&xPtr); Y.ExtractView(&yPtr); #ifdef HAVE_IFPACK_EPETRAEXT EpetraExt_PointToBlockDiagPermute* IBD=0; if (UseBlockMode_) IBD=&*InvBlockDiagonal_; #endif //--- Do a quick solve when the matrix is identity double *invDiag=0; if(!UseBlockMode_) invDiag=InvDiagonal_->Values(); if ((LambdaMin_ == 1.0) && (LambdaMax_ == LambdaMin_)) { #ifdef HAVE_IFPACK_EPETRAEXT if(UseBlockMode_) IBD->ApplyInverse(*Xcopy,Y); else #endif if (nVec == 1) { double *yPointer = yPtr[0], *xPointer = xPtr[0]; for (int i = 0; i < len; ++i) yPointer[i] = xPointer[i]*invDiag[i]; } else { int i, k; for (i = 0; i < len; ++i) { double coeff = invDiag[i]; for (k = 0; k < nVec; ++k) yPtr[k][i] = xPtr[k][i] * coeff; } } // if (nVec == 1) return 0; } // if ((LambdaMin_ == 1.0) && (LambdaMax_ == LambdaMin_)) //--- Initialize coefficients // Note that delta stores the inverse of ML_Cheby::delta double alpha = LambdaMax_ / EigRatio_; double beta = 1.1 * LambdaMax_; double delta = 2.0 / (beta - alpha); double theta = 0.5 * (beta + alpha); double s1 = theta * delta; //--- Define vectors // In ML_Cheby, V corresponds to pAux and W to dk Epetra_MultiVector V(X); Epetra_MultiVector W(X); #ifdef HAVE_IFPACK_EPETRAEXT Epetra_MultiVector Temp(X); #endif double *vPointer = V.Values(), *wPointer = W.Values(); double oneOverTheta = 1.0/theta; int i, j, k; //--- If solving normal equations, multiply RHS by A^T if(SolveNormalEquations_){ Apply_Transpose(Operator_,Y,V); Y=V; } // Do the smoothing when block scaling is turned OFF // --- Treat the initial guess if (ZeroStartingSolution_ == false) { Operator_->Apply(Y, V); // Compute W = invDiag * ( X - V )/ Theta #ifdef HAVE_IFPACK_EPETRAEXT if(UseBlockMode_) { Temp.Update(oneOverTheta,X,-oneOverTheta,V,0.0); IBD->ApplyInverse(Temp,W); // Perform additional matvecs for normal equations // CMS: Testing this only in block mode FOR NOW if(SolveNormalEquations_){ IBD->ApplyInverse(W,Temp); Apply_Transpose(Operator_,Temp,W); } } else #endif if (nVec == 1) { double *xPointer = xPtr[0]; for (i = 0; i < len; ++i) wPointer[i] = invDiag[i] * (xPointer[i] - vPointer[i]) * oneOverTheta; } else { for (i = 0; i < len; ++i) { double coeff = invDiag[i]*oneOverTheta; double *wi = wPointer + i, *vi = vPointer + i; for (k = 0; k < nVec; ++k) { *wi = (xPtr[k][i] - (*vi)) * coeff; wi = wi + len; vi = vi + len; } } } // if (nVec == 1) // Update the vector Y Y.Update(1.0, W, 1.0); } else { // Compute W = invDiag * X / Theta #ifdef HAVE_IFPACK_EPETRAEXT if(UseBlockMode_) { IBD->ApplyInverse(X,W); // Perform additional matvecs for normal equations // CMS: Testing this only in block mode FOR NOW if(SolveNormalEquations_){ IBD->ApplyInverse(W,Temp); Apply_Transpose(Operator_,Temp,W); } W.Scale(oneOverTheta); Y.Update(1.0, W, 0.0); } else #endif if (nVec == 1) { double *xPointer = xPtr[0]; for (i = 0; i < len; ++i){ wPointer[i] = invDiag[i] * xPointer[i] * oneOverTheta; } memcpy(yPtr[0], wPointer, len*sizeof(double)); } else { for (i = 0; i < len; ++i) { double coeff = invDiag[i]*oneOverTheta; double *wi = wPointer + i; for (k = 0; k < nVec; ++k) { *wi = xPtr[k][i] * coeff; wi = wi + len; } } for (k = 0; k < nVec; ++k) memcpy(yPtr[k], wPointer + k*len, len*sizeof(double)); } // if (nVec == 1) } // if (ZeroStartingSolution_ == false) //--- Apply the polynomial double rhok = 1.0/s1, rhokp1; double dtemp1, dtemp2; int degreeMinusOne = PolyDegree_ - 1; if (nVec == 1) { double *xPointer = xPtr[0]; for (k = 0; k < degreeMinusOne; ++k) { Operator_->Apply(Y, V); rhokp1 = 1.0 / (2.0*s1 - rhok); dtemp1 = rhokp1 * rhok; dtemp2 = 2.0 * rhokp1 * delta; rhok = rhokp1; // Compute W = dtemp1 * W W.Scale(dtemp1); // Compute W = W + dtemp2 * invDiag * ( X - V ) #ifdef HAVE_IFPACK_EPETRAEXT if(UseBlockMode_) { //NTS: We can clobber V since it will be reset in the Apply V.Update(dtemp2,X,-dtemp2); IBD->ApplyInverse(V,Temp); // Perform additional matvecs for normal equations // CMS: Testing this only in block mode FOR NOW if(SolveNormalEquations_){ IBD->ApplyInverse(V,Temp); Apply_Transpose(Operator_,Temp,V); } W.Update(1.0,Temp,1.0); } else{ #endif for (i = 0; i < len; ++i) wPointer[i] += dtemp2* invDiag[i] * (xPointer[i] - vPointer[i]); #ifdef HAVE_IFPACK_EPETRAEXT } #endif // Update the vector Y Y.Update(1.0, W, 1.0); } // for (k = 0; k < degreeMinusOne; ++k) } else { for (k = 0; k < degreeMinusOne; ++k) { Operator_->Apply(Y, V); rhokp1 = 1.0 / (2.0*s1 - rhok); dtemp1 = rhokp1 * rhok; dtemp2 = 2.0 * rhokp1 * delta; rhok = rhokp1; // Compute W = dtemp1 * W W.Scale(dtemp1); // Compute W = W + dtemp2 * invDiag * ( X - V ) #ifdef HAVE_IFPACK_EPETRAEXT if(UseBlockMode_) { //We can clobber V since it will be reset in the Apply V.Update(dtemp2,X,-dtemp2); IBD->ApplyInverse(V,Temp); // Perform additional matvecs for normal equations // CMS: Testing this only in block mode FOR NOW if(SolveNormalEquations_){ IBD->ApplyInverse(V,Temp); Apply_Transpose(Operator_,Temp,V); } W.Update(1.0,Temp,1.0); } else{ #endif for (i = 0; i < len; ++i) { double coeff = invDiag[i]*dtemp2; double *wi = wPointer + i, *vi = vPointer + i; for (j = 0; j < nVec; ++j) { *wi += (xPtr[j][i] - (*vi)) * coeff; wi = wi + len; vi = vi + len; } } #ifdef HAVE_IFPACK_EPETRAEXT } #endif // Update the vector Y Y.Update(1.0, W, 1.0); } // for (k = 0; k < degreeMinusOne; ++k) } // if (nVec == 1) // Flops are updated in each of the following. ++NumApplyInverse_; ApplyInverseTime_ += Time_->ElapsedTime(); return(0); }