//============================================================================= int Ifpack_IKLU::ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-2); // compute preconditioner first if (X.NumVectors() != Y.NumVectors()) IFPACK_CHK_ERR(-3); // Return error: X and Y not the same size Time_.ResetStartTime(); // NOTE: L_ and U_ are 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. // // AztecOO gives X and Y pointing to the same memory location, // need to create an auxiliary vector, Xcopy and apply permutation. vector<int> invq( NumMyRows_ ); for (int i=0; i<NumMyRows_; ++i ) { csrnN_->perm[ csrnN_->pinv[i] ] = i; invq[ cssS_->q[i] ] = i; } Teuchos::RefCountPtr<Epetra_MultiVector> Xcopy = Teuchos::rcp( new Epetra_MultiVector(X.Map(),X.NumVectors()), false ); Teuchos::RefCountPtr<Epetra_MultiVector> Ytemp = Teuchos::rcp( new Epetra_MultiVector(Y.Map(),Y.NumVectors()) ); for (int i=0; i<NumMyRows_; ++i) { for (int j=0; j<X.NumVectors(); ++j) { Xcopy->ReplaceMyValue( invq[i], j, (*X(j))[i] ); } } if (!UseTranspose_) { // solves LU Y = X IFPACK_CHK_ERR(L_->Solve(false,false,false,*Xcopy,*Ytemp)); IFPACK_CHK_ERR(U_->Solve(true,false,false,*Ytemp,*Ytemp)); } else { // solves U(trans) L(trans) Y = X IFPACK_CHK_ERR(U_->Solve(true,true,false,*Xcopy,*Ytemp)); IFPACK_CHK_ERR(L_->Solve(false,true,false,*Ytemp,*Ytemp)); } // Reverse the permutation. for (int i=0; i<NumMyRows_; ++i) { for (int j=0; j<Y.NumVectors(); ++j) { Y.ReplaceMyValue( csrnN_->perm[i], j, (*(*Ytemp)(j))[i] ); } } ++NumApplyInverse_; #ifdef IFPACK_FLOPCOUNTERS ApplyInverseFlops_ += X.NumVectors() * 2 * GlobalNonzeros_; #endif ApplyInverseTime_ += Time_.ElapsedTime(); return(0); }