// ================================================ ====== ==== ==== == = //! Implicitly applies in the inverse in an 1-2-1 format int ML_Epetra::RefMaxwellPreconditioner::ApplyInverse_Implicit_121(const Epetra_MultiVector& B, Epetra_MultiVector& X) const { #ifdef ML_TIMING double t_time,t_diff; StartTimer(&t_time); #endif int NumVectors=B.NumVectors(); Epetra_MultiVector TempE1(X.Map(),NumVectors,false); Epetra_MultiVector TempE2(X.Map(),NumVectors,true); Epetra_MultiVector TempN1(*NodeMap_,NumVectors,false); Epetra_MultiVector TempN2(*NodeMap_,NumVectors,true); Epetra_MultiVector Resid(B); /* Pre-Smoothing */ ML_CHK_ERR(PreEdgeSmoother->ApplyInverse(B,X)); /* Precondition (1,1) Block */ ML_CHK_ERR(EdgePC->ApplyInverse(Resid,TempE2)); ML_CHK_ERR(X.Update(1.0,TempE2,1.0));; /* Build Residual */ ML_CHK_ERR(SM_Matrix_->Multiply(false,X,TempE1)); ML_CHK_ERR(Resid.Update(-1.0,TempE1,1.0,B,0.0)); if(!HasOnlyDirichletNodes){ ML_CHK_ERR(D0_Matrix_->Multiply(true,Resid,TempN1)); } /* Precondition (2,2) Block */ if(!HasOnlyDirichletNodes){ ML_CHK_ERR(NodePC->ApplyInverse(TempN1,TempN2)); D0_Matrix_->Multiply(false,TempN2,TempE1); }/*end if*/ if(!HasOnlyDirichletNodes) X.Update(1.0,TempE1,1.0); /* Build Residual */ ML_CHK_ERR(SM_Matrix_->Multiply(false,X,TempE1)); ML_CHK_ERR(Resid.Update(-1.0,TempE1,1.0,B,0.0)); /* Precondition (1,1) Block */ TempE2.PutScalar(0.0); ML_CHK_ERR(EdgePC->ApplyInverse(Resid,TempE2)); ML_CHK_ERR(X.Update(1.0,TempE2,1.0));; /* Post-Smoothing */ ML_CHK_ERR(PostEdgeSmoother->ApplyInverse(B,X)); #ifdef ML_TIMING StopTimer(&t_time,&t_diff); /* Output */ ML_Comm *comm_; ML_Comm_Create(&comm_); this->ApplicationTime_+= t_diff; ML_Comm_Destroy(&comm_); #endif return 0; }
//============================================================================== int LinearProblem_CrsSingletonFilter::ComputeFullSolution() { int jj, k; Epetra_MultiVector * FullLHS = FullProblem()->GetLHS(); Epetra_MultiVector * FullRHS = FullProblem()->GetRHS(); tempX_->PutScalar(0.0); tempExportX_->PutScalar(0.0); // Inject values that the user computed for the reduced problem into the full solution vector EPETRA_CHK_ERR(tempX_->Export(*ReducedLHS_, *Full2ReducedLHSImporter_, Add)); FullLHS->Update(1.0, *tempX_, 1.0); // Next we will use our full solution vector which is populated with pre-filter solution // values and reduced system solution values to compute the sum of the row contributions // that must be subtracted to get the post-filter solution values EPETRA_CHK_ERR(FullMatrix()->Multiply(false, *FullLHS, *tempB_)); // Finally we loop through the local rows that were associated with column singletons and compute the // solution for these equations. int NumVectors = tempB_->NumVectors(); for (k=0; k<NumMyColSingletons_; k++) { int i = ColSingletonRowLIDs_[k]; int j = ColSingletonColLIDs_[k]; double pivot = ColSingletonPivots_[k]; for (jj=0; jj<NumVectors; jj++) (*tempExportX_)[jj][j]= ((*FullRHS)[jj][i] - (*tempB_)[jj][i])/pivot; } // Finally, insert values from post-solve step and we are done!!!! if (FullMatrix()->RowMatrixImporter()!=0) { EPETRA_CHK_ERR(tempX_->Export(*tempExportX_, *FullMatrix()->RowMatrixImporter(), Add)); } else { tempX_->Update(1.0, *tempExportX_, 0.0); } FullLHS->Update(1.0, *tempX_, 1.0); return(0); }
// ================================================ ====== ==== ==== == = //! Implicitly applies in the inverse in a 2-1-2 format int ML_Epetra::RefMaxwellPreconditioner::ApplyInverse_Implicit_212(const Epetra_MultiVector& B, Epetra_MultiVector& X) const { #ifdef ML_TIMING double t_time,t_diff; StartTimer(&t_time); #endif int NumVectors=B.NumVectors(); /* Setup Temps */ Epetra_MultiVector node_sol1(*NodeMap_,NumVectors,true); Epetra_MultiVector node_sol2(*NodeMap_,NumVectors,false); Epetra_MultiVector node_rhs(*NodeMap_,NumVectors,false); Epetra_MultiVector edge_temp1(*DomainMap_,NumVectors,false); Epetra_MultiVector edge_rhs(*DomainMap_,NumVectors,false); Epetra_MultiVector edge_sol(*DomainMap_,NumVectors,true); /* Build Nodal RHS */ ML_CHK_ERR(D0_Matrix_->Multiply(true,B,node_rhs)); /* Precondition (2,2) Block */ ML_CHK_ERR(NodePC->ApplyInverse(node_rhs,node_sol1)); /* Build Residual */ ML_CHK_ERR(D0_Matrix_->Multiply(false,node_sol1,edge_temp1)); ML_CHK_ERR(edge_rhs.Update(1.0,B,-1.0)); /* Precondition (1,1) Block */ // _CHK_ERR(PreEdgeSmoother->ApplyInverse(B,X)); ML_CHK_ERR(EdgePC->ApplyInverse(edge_rhs,edge_sol)); /* Build Nodal RHS */ ML_CHK_ERR(edge_temp1.Update(1.0,edge_rhs,-1.0)); ML_CHK_ERR(D0_Matrix_->Multiply(true,edge_temp1,node_rhs)); /* Precondition (2,2) Block */ ML_CHK_ERR(NodePC->ApplyInverse(node_rhs,node_sol2)); /* Assemble solution (x = xe + T*(xn1 + xn2)) */ ML_CHK_ERR(node_sol1.Update(1.0,node_sol2,1.0)); ML_CHK_ERR(D0_Matrix_->Multiply(false,node_sol1,X)); ML_CHK_ERR(X.Update(1.0,edge_sol,1.0)); #ifdef ML_TIMING StopTimer(&t_time,&t_diff); /* Output */ ML_Comm *comm_; ML_Comm_Create(&comm_); this->ApplicationTime_+= t_diff; ML_Comm_Destroy(&comm_); #endif return 0; }/*end ApplyInverse_Implicit_212*/
//============================================================================== int Ifpack_Polynomial:: ApplyInverse(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { if (!IsComputed()) IFPACK_CHK_ERR(-3); if (PolyDegree_ == 0) return 0; int nVec = X.NumVectors(); if (nVec != Y.NumVectors()) IFPACK_CHK_ERR(-2); Time_->ResetStartTime(); Epetra_MultiVector Xcopy(X); if(ZeroStartingSolution_==true) { Y.PutScalar(0.0); } // mfh 20 Mar 2014: IBD never gets used, so I'm commenting out the // following lines of code in order to forestall build warnings. // #ifdef HAVE_IFPACK_EPETRAEXT // EpetraExt_PointToBlockDiagPermute* IBD=0; // if (UseBlockMode_) IBD=&*InvBlockDiagonal_; // #endif Y.Update(-coeff_[1], Xcopy, 1.0); for (int ii = 2; ii < static_cast<int> (coeff_.size ()); ++ii) { const Epetra_MultiVector V(Xcopy); Operator_->Apply(V,Xcopy); Xcopy.Multiply(1.0, *InvDiagonal_, Xcopy, 0.0); // Update Y Y.Update(-coeff_[ii], Xcopy, 1.0); } // Flops are updated in each of the following. ++NumApplyInverse_; ApplyInverseTime_ += Time_->ElapsedTime(); return(0); }
// ============================================================================ int ML_Epetra::MatrixFreePreconditioner:: ApplyJacobi(Epetra_MultiVector& X, const Epetra_MultiVector& B, const double omega, Epetra_MultiVector& tmp) const { Operator_.Apply(X, tmp); tmp.Update(1.0, B, -1.0); ML_CHK_ERR(X.Multiply((double)omega, *InvPointDiagonal_, tmp, 1.0)); ///ML_CHK_ERR(X.Multiply('T', 'N', (double)omega, *InvPointDiagonal_, tmp, 1.0)); return(0); }
// ============================================================================ int ML_Epetra::MatrixFreePreconditioner:: ApplyBlockJacobi(Epetra_MultiVector& X, const Epetra_MultiVector& B, const double omega, Epetra_MultiVector& tmp) const { Operator_.Apply(X, tmp); tmp.Update(1.0, B, -1.0); ML_CHK_ERR(ApplyInvBlockDiag(omega, X, 1.0, tmp)); ///ML_CHK_ERR(X.Multiply('T', 'N', omega, *InvBlockDiag_, tmp, 1.0)); return(0); }
void MxGeoMultigridPrec::removeConstField(Epetra_MultiVector & x) const { //x.Comm().Barrier(); Epetra_MultiVector ones(x); double dotProd, norm; ones.PutScalar(1); ones.Norm2(&norm); x.Dot(ones, &dotProd); //std::cout << "norm = " << norm << ", dotProd = " << dotProd << "\n"; x.Update(-dotProd / norm / norm, ones, 1.); x.Dot(ones, &dotProd); //std::cout << "const vec part: " << dotProd << "\n"; }
// ================================================ ====== ==== ==== == = // Computes Y= <me> * X int ML_Epetra::ML_RefMaxwell_11_Operator::Apply(const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { Epetra_MultiVector temp(X); /* Do the SM part */ SM_Matrix_->Apply(X,Y); /* Do the Addon part */ Addon_->Apply(X,temp); /* Sum things together*/ Y.Update(1,temp,1); return 0; }/*end Apply*/
// return x = (I - op/rhomax)*x in x void MxGeoMultigridPrec::smoothInterpolation(int level, Epetra_MultiVector & x) const { Epetra_MultiVector xtmp(x); // get matrix diagonal Epetra_Vector diag(ops[level]->RangeMap()); ops[level]->ExtractDiagonalCopy(diag); //diag.Reciprocal(diag); ops[level]->Apply(x, xtmp); // xtmp = op*x xtmp.ReciprocalMultiply(1.0, diag, xtmp, 0.0); //xtmp.Scale(1.3333 / maxEigs[level]); // xtmp = (op/rhomax)*x xtmp.Scale(0.5 * 1.3333); // xtmp = (op/rhomax)*x (rhomax is usually 2) x.Update(-1.0, xtmp, 1.0); // x = x - xtmp }
void Stokhos::EpetraMultiVectorOrthogPoly:: assignToBlockMultiVector(Epetra_MultiVector& v) const { if (this->size() > 0) { if (bv != Teuchos::null) v.Update(1.0, *bv, 0.0); else { EpetraExt::BlockMultiVector block_v(View, this->coeff_[0]->Map(), v); for (int i=0; i<this->size(); i++) *(block_v.GetBlock(i)) = *(coeff_[i]); } } }
int Stokhos::ProductEpetraOperator:: Apply(const Epetra_MultiVector& Input, Epetra_MultiVector& Result) const { if (useTranspose) { EpetraExt::BlockMultiVector sg_input(View, *range_base_map, Input); Epetra_MultiVector tmp(Result.Map(), Result.NumVectors()); Result.PutScalar(0.0); for (int i=0; i<coeff_.size(); i++) { coeff_[i]->Apply(*(sg_input.GetBlock(i)), tmp); Result.Update(1.0, tmp, 1.0); } } else { EpetraExt::BlockMultiVector sg_result(View, *range_base_map, Result); for (int i=0; i<coeff_.size(); i++) coeff_[i]->Apply(Input, *(sg_result.GetBlock(i))); } return 0; }
//! Update vector static void update(Epetra_MultiVector& vec, double a, const Epetra_MultiVector& x) { vec.Update(a,x,1.0); }
// ================================================ ====== ==== ==== == = //! Implicitly applies in the inverse in an additive format int ML_Epetra::RefMaxwellPreconditioner::ApplyInverse_Implicit_Additive(const Epetra_MultiVector& B, Epetra_MultiVector& X) const { #ifdef ML_TIMING double t_time,t_diff; StartTimer(&t_time); #endif int NumVectors=B.NumVectors(); Epetra_MultiVector TempE1(X.Map(),NumVectors,false); Epetra_MultiVector TempE2(X.Map(),NumVectors,true); Epetra_MultiVector TempN1(*NodeMap_,NumVectors,false); Epetra_MultiVector TempN2(*NodeMap_,NumVectors,true); Epetra_MultiVector Resid(B.Map(),NumVectors); /* Pre-Smoothing */ #ifdef HAVE_ML_IFPACK if(IfSmoother) {ML_CHK_ERR(IfSmoother->ApplyInverse(B,X));} else #endif if(PreEdgeSmoother) ML_CHK_ERR(PreEdgeSmoother->ApplyInverse(B,X)); /* Build Residual */ ML_CHK_ERR(SM_Matrix_->Multiply(false,X,TempE1)); ML_CHK_ERR(Resid.Update(-1.0,TempE1,1.0,B,0.0)); if(!HasOnlyDirichletNodes){ ML_CHK_ERR(D0_Matrix_->Multiply(true,Resid,TempN1)); } /* Precondition (1,1) block (additive)*/ ML_CHK_ERR(EdgePC->ApplyInverse(Resid,TempE2)); /* Precondition (2,2) block (additive)*/ if(!HasOnlyDirichletNodes){ ML_CHK_ERR(NodePC->ApplyInverse(TempN1,TempN2)); /* EXPERIMENTAL: Local Nodal Stuff, if active */ if(use_local_nodal_solver){ const Epetra_Map& LocalMap=LocalNodalMatrix->DomainMap(); Epetra_MultiVector TempNL1(LocalMap,NumVectors,true); Epetra_MultiVector TempNL2(LocalMap,NumVectors,true); Epetra_MultiVector TempN3(*NodeMap_,NumVectors,true); NodesToLocalNodes->Multiply(true,TempN1,TempNL1); LocalNodalSolver->ApplyInverse(TempNL1,TempNL2); NodesToLocalNodes->Multiply(false,TempNL2,TempN3); TempN2.Update(1.0,TempN3,1.0); }/*end if*/ D0_Matrix_->Multiply(false,TempN2,TempE1); }/*end if*/ /* Update solution */ if(HasOnlyDirichletNodes) X.Update(1.0,TempE2,1.0); else X.Update(1.0,TempE1,1.0,TempE2,1.0); /* Post-Smoothing */ #ifdef HAVE_ML_IFPACK if(IfSmoother) {ML_CHK_ERR(IfSmoother->ApplyInverse(B,X));} else #endif if(PostEdgeSmoother) ML_CHK_ERR(PostEdgeSmoother->ApplyInverse(B,X)); #ifdef ML_TIMING StopTimer(&t_time,&t_diff); /* Output */ ML_Comm *comm_; ML_Comm_Create(&comm_); this->ApplicationTime_+= t_diff; ML_Comm_Destroy(&comm_); #endif return 0; }
int FSIExactJacobian::Epetra_ExactJacobian::Apply (const Epetra_MultiVector& X, Epetra_MultiVector& Y) const { LifeChrono chronoFluid, chronoSolid, chronoInterface; M_comm->Barrier(); double xnorm = 0.; X.NormInf (&xnorm); Epetra_FEVector dz (Y.Map() ); if (M_ej->isSolid() ) { std::cout << "\n ***** norm (z)= " << xnorm << std::endl << std::endl; } if ( xnorm == 0.0 ) { Y.Scale (0.); dz.Scale (0.); } else { vector_Type const z (X, M_ej->solidInterfaceMap(), Unique); M_ej->displayer().leaderPrint ( "NormInf res " , z.normInf(), "\n" ); //M_ej->solid().residual() *= 0.; //M_ej->transferInterfaceOnSolid(z, M_ej->solid().residual()); //std::cout << "NormInf res_d " << M_ej->solid().residual().NormInf() << std::endl; //if (M_ej->isSolid()) // M_ej->solid().postProcess(); M_ej->setLambdaFluid (z); //M_ej->transferInterfaceOnSolid(z, M_ej->solid().disp()); chronoInterface.start(); vector_Type sigmaFluidUnique (M_ej->sigmaFluid(), Unique); chronoInterface.stop(); M_comm->Barrier(); chronoFluid.start(); if (M_ej->isFluid() ) { //to be used when we correct the other lines if (true || ( !this->M_ej->dataFluid()->isSemiImplicit() /*|| this->M_ej->dataFluid().semiImplicit()==-1*/) ) { M_ej->meshMotion().iterate (*M_ej->BCh_harmonicExtension() ); //std::cout<<" mesh motion iterated!!!"<<std::endl; } M_ej->displayer().leaderPrint ( " norm inf dx = " , M_ej->meshMotion().disp().normInf(), "\n" ); M_ej->solveLinearFluid(); M_ej->transferFluidOnInterface (M_ej->fluid().residual(), sigmaFluidUnique); //M_ej->fluidPostProcess(); } M_comm->Barrier(); chronoFluid.stop(); M_ej->displayer().leaderPrintMax ( "Fluid linear solution: total time : ", chronoFluid.diff() ); chronoInterface.start(); // M_ej->setSigmaFluid(sigmaFluidUnique); M_ej->setSigmaSolid (sigmaFluidUnique); vector_Type lambdaSolidUnique (M_ej->lambdaSolid(), Unique); chronoInterface.stop(); M_comm->Barrier(); chronoFluid.start(); if (M_ej->isSolid() ) { M_ej->solveLinearSolid(); M_ej->transferSolidOnInterface (M_ej->solid().displacement(), lambdaSolidUnique); } M_comm->Barrier(); chronoSolid.stop(); M_ej->displayer().leaderPrintMax ( "Solid linear solution: total time : " , chronoSolid.diff() ); chronoInterface.start(); M_ej->setLambdaSolid (lambdaSolidUnique); chronoInterface.stop(); M_ej->displayer().leaderPrintMax ( "Interface linear transfer: total time : " , chronoInterface.diffCumul() ); dz = lambdaSolidUnique.epetraVector(); } Y = X; Y.Update (1., dz, -1.); double ynorm; Y.NormInf (&ynorm); if (M_ej->isSolid() ) std::cout << "\n\n ***** norm (Jz)= " << ynorm << std::endl << std::endl; return 0; }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv, 0); Epetra_MpiComm Comm(MPI_COMM_WORLD); #else Epetra_SerialComm Comm; #endif int nProcs, myPID ; Teuchos::ParameterList pLUList ; // ParaLU parameters Teuchos::ParameterList isoList ; // Isorropia parameters string ipFileName = "ShyLU.xml"; // TODO : Accept as i/p nProcs = mpiSession.getNProc(); myPID = Comm.MyPID(); if (myPID == 0) { cout <<"Parallel execution: nProcs="<< nProcs << endl; } // =================== Read input xml file ============================= Teuchos::updateParametersFromXmlFile(ipFileName, &pLUList); isoList = pLUList.sublist("Isorropia Input"); // Get matrix market file name string MMFileName = Teuchos::getParameter<string>(pLUList, "mm_file"); string prec_type = Teuchos::getParameter<string>(pLUList, "preconditioner"); if (myPID == 0) { cout << "Input :" << endl; cout << "ParaLU params " << endl; pLUList.print(std::cout, 2, true, true); cout << "Matrix market file name: " << MMFileName << endl; } // ==================== Read input Matrix ============================== Epetra_CrsMatrix *A; int err = EpetraExt::MatrixMarketFileToCrsMatrix(MMFileName.c_str(), Comm, A); //EpetraExt::MatlabFileToCrsMatrix(MMFileName.c_str(), Comm, A); //assert(err != 0); cout <<"Done reading the matrix"<< endl; int n = A->NumGlobalRows(); cout <<"n="<< n << endl; // Create input vectors Epetra_Map vecMap(n, 0, Comm); Epetra_MultiVector x(vecMap, 1); Epetra_MultiVector b(vecMap, 1, false); b.PutScalar(1.0); // TODO : Accept it as input // Partition the matrix with hypergraph partitioning and redisstribute Isorropia::Epetra::Partitioner *partitioner = new Isorropia::Epetra::Partitioner(A, isoList, false); partitioner->partition(); Isorropia::Epetra::Redistributor rd(partitioner); Epetra_CrsMatrix *newA; Epetra_MultiVector *newX, *newB; rd.redistribute(*A, newA); delete A; A = newA; rd.redistribute(x, newX); rd.redistribute(b, newB); Epetra_LinearProblem problem(A, newX, newB); Amesos Factory; char* SolverType = "Amesos_Klu"; bool IsAvailable = Factory.Query(SolverType); Epetra_LinearProblem *LP = new Epetra_LinearProblem(); LP->SetOperator(A); LP->SetLHS(newX); LP->SetRHS(newB); Amesos_BaseSolver *Solver = Factory.Create(SolverType, *LP); Solver->SymbolicFactorization(); Teuchos::Time ftime("setup time"); ftime.start(); Solver->NumericFactorization(); cout << "Numeric Factorization" << endl; Solver->Solve(); cout << "Solve done" << endl; ftime.stop(); cout << "Time to setup" << ftime.totalElapsedTime() << endl; // compute ||Ax - b|| double Norm; Epetra_MultiVector Ax(vecMap, 1); Epetra_MultiVector *newAx; rd.redistribute(Ax, newAx); A->Multiply(false, *newX, *newAx); newAx->Update(1.0, *newB, -1.0); newAx->Norm2(&Norm); double ANorm = A->NormOne(); cout << "|Ax-b |/|A| = " << Norm/ANorm << endl; delete newAx; delete newX; delete newB; delete A; delete partitioner; }
//============================================================================== int LinearProblem_CrsSingletonFilter::UpdateReducedProblem(Epetra_LinearProblem * Problem) { int i, j; if (Problem==0) EPETRA_CHK_ERR(-1); // Null problem pointer FullProblem_ = Problem; FullMatrix_ = dynamic_cast<Epetra_RowMatrix *>(Problem->GetMatrix()); if (FullMatrix_==0) EPETRA_CHK_ERR(-2); // Need a RowMatrix if (Problem->GetRHS()==0) EPETRA_CHK_ERR(-3); // Need a RHS if (Problem->GetLHS()==0) EPETRA_CHK_ERR(-4); // Need a LHS if (!HaveReducedProblem_) EPETRA_CHK_ERR(-5); // Must have set up reduced problem // Create pointer to Full RHS, LHS Epetra_MultiVector * FullRHS = FullProblem()->GetRHS(); Epetra_MultiVector * FullLHS = FullProblem()->GetLHS(); int NumVectors = FullLHS->NumVectors(); int NumEntries; int * Indices; double * Values; int NumMyRows = FullMatrix()->NumMyRows(); int ColSingletonCounter = 0; for (i=0; i<NumMyRows; i++) { int curGRID = FullMatrixRowMap().GID(i); if (ReducedMatrixRowMap()->MyGID(curGRID)) { // Check if this row should go into reduced matrix EPETRA_CHK_ERR(GetRowGCIDs(i, NumEntries, Values, Indices)); // Get current row (indices global) int ierr = ReducedMatrix()->ReplaceGlobalValues(curGRID, NumEntries, Values, Indices); // Positive errors will occur because we are submitting col entries that are not part of // reduced system. However, because we specified a column map to the ReducedMatrix constructor // these extra column entries will be ignored and we will be politely reminded by a positive // error code if (ierr<0) EPETRA_CHK_ERR(ierr); } // Otherwise if singleton row we explicitly eliminate this row and solve for corresponding X value else { EPETRA_CHK_ERR(GetRow(i, NumEntries, Values, Indices)); // Get current row if (NumEntries==1) { double pivot = Values[0]; if (pivot==0.0) EPETRA_CHK_ERR(-1); // Encountered zero row, unable to continue int indX = Indices[0]; for (j=0; j<NumVectors; j++) (*tempExportX_)[j][indX] = (*FullRHS)[j][i]/pivot; } // Otherwise, this is a singleton column and we will scan for the pivot element needed // for post-solve equations else { j = ColSingletonPivotLIDs_[ColSingletonCounter]; double pivot = Values[j]; if (pivot==0.0) EPETRA_CHK_ERR(-2); // Encountered zero column, unable to continue ColSingletonPivots_[ColSingletonCounter] = pivot; ColSingletonCounter++; } } } assert(ColSingletonCounter==NumMyColSingletons_); // Sanity test // Update Reduced LHS (Puts any initial guess values into reduced system) ReducedLHS_->PutScalar(0.0); // zero out Reduced LHS EPETRA_CHK_ERR(ReducedLHS_->Import(*FullLHS, *Full2ReducedLHSImporter_, Insert)); FullLHS->PutScalar(0.0); // zero out Full LHS since we will inject values as we get them // Construct Reduced RHS // Zero out temp space tempX_->PutScalar(0.0); tempB_->PutScalar(0.0); //Inject known X values into tempX for purpose of computing tempB = FullMatrix*tempX // Also inject into full X since we already know the solution if (FullMatrix()->RowMatrixImporter()!=0) { EPETRA_CHK_ERR(tempX_->Export(*tempExportX_, *FullMatrix()->RowMatrixImporter(), Add)); EPETRA_CHK_ERR(FullLHS->Export(*tempExportX_, *FullMatrix()->RowMatrixImporter(), Add)); } else { tempX_->Update(1.0, *tempExportX_, 0.0); FullLHS->Update(1.0, *tempExportX_, 0.0); } EPETRA_CHK_ERR(FullMatrix()->Multiply(false, *tempX_, *tempB_)); EPETRA_CHK_ERR(tempB_->Update(1.0, *FullRHS, -1.0)); // tempB now has influence of already-known X values ReducedRHS_->PutScalar(0.0); EPETRA_CHK_ERR(ReducedRHS_->Import(*tempB_, *Full2ReducedRHSImporter_, Insert)); return(0); }
//============================================================================== int LinearProblem_CrsSingletonFilter::ConstructReducedProblem(Epetra_LinearProblem * Problem) { int i, j; if (HaveReducedProblem_) EPETRA_CHK_ERR(-1); // Setup already done once. Cannot do it again if (Problem==0) EPETRA_CHK_ERR(-2); // Null problem pointer FullProblem_ = Problem; FullMatrix_ = dynamic_cast<Epetra_RowMatrix *>(Problem->GetMatrix()); if (FullMatrix_==0) EPETRA_CHK_ERR(-3); // Need a RowMatrix if (Problem->GetRHS()==0) EPETRA_CHK_ERR(-4); // Need a RHS if (Problem->GetLHS()==0) EPETRA_CHK_ERR(-5); // Need a LHS // Generate reduced row and column maps Epetra_MapColoring & RowMapColors = *RowMapColors_; Epetra_MapColoring & ColMapColors = *ColMapColors_; ReducedMatrixRowMap_ = RowMapColors.GenerateMap(0); ReducedMatrixColMap_ = ColMapColors.GenerateMap(0); // Create domain and range map colorings by exporting map coloring of column and row maps if (FullMatrix()->RowMatrixImporter()!=0) { Epetra_MapColoring DomainMapColors(FullMatrixDomainMap()); EPETRA_CHK_ERR(DomainMapColors.Export(*ColMapColors_, *FullMatrix()->RowMatrixImporter(), AbsMax)); OrigReducedMatrixDomainMap_ = DomainMapColors.GenerateMap(0); } else OrigReducedMatrixDomainMap_ = ReducedMatrixColMap_; if (FullMatrixIsCrsMatrix_) { if (FullCrsMatrix()->Exporter()!=0) { // Non-trivial exporter Epetra_MapColoring RangeMapColors(FullMatrixRangeMap()); EPETRA_CHK_ERR(RangeMapColors.Export(*RowMapColors_, *FullCrsMatrix()->Exporter(), AbsMax)); ReducedMatrixRangeMap_ = RangeMapColors.GenerateMap(0); } else ReducedMatrixRangeMap_ = ReducedMatrixRowMap_; } else ReducedMatrixRangeMap_ = ReducedMatrixRowMap_; // Check to see if the reduced system domain and range maps are the same. // If not, we need to remap entries of the LHS multivector so that they are distributed // conformally with the rows of the reduced matrix and the RHS multivector SymmetricElimination_ = ReducedMatrixRangeMap_->SameAs(*OrigReducedMatrixDomainMap_); if (!SymmetricElimination_) ConstructRedistributeExporter(OrigReducedMatrixDomainMap_, ReducedMatrixRangeMap_, RedistributeDomainExporter_, ReducedMatrixDomainMap_); else { ReducedMatrixDomainMap_ = OrigReducedMatrixDomainMap_; OrigReducedMatrixDomainMap_ = 0; RedistributeDomainExporter_ = 0; } // Create pointer to Full RHS, LHS Epetra_MultiVector * FullRHS = FullProblem()->GetRHS(); Epetra_MultiVector * FullLHS = FullProblem()->GetLHS(); int NumVectors = FullLHS->NumVectors(); // Create importers // cout << "RedDomainMap\n"; // cout << *ReducedMatrixDomainMap(); // cout << "FullDomainMap\n"; // cout << FullMatrixDomainMap(); Full2ReducedLHSImporter_ = new Epetra_Import(*ReducedMatrixDomainMap(), FullMatrixDomainMap()); // cout << "RedRowMap\n"; // cout << *ReducedMatrixRowMap(); // cout << "FullRHSMap\n"; // cout << FullRHS->Map(); Full2ReducedRHSImporter_ = new Epetra_Import(*ReducedMatrixRowMap(), FullRHS->Map()); // Construct Reduced Matrix ReducedMatrix_ = new Epetra_CrsMatrix(Copy, *ReducedMatrixRowMap(), *ReducedMatrixColMap(), 0); // Create storage for temporary X values due to explicit elimination of rows tempExportX_ = new Epetra_MultiVector(FullMatrixColMap(), NumVectors); int NumEntries; int * Indices; double * Values; int NumMyRows = FullMatrix()->NumMyRows(); int ColSingletonCounter = 0; for (i=0; i<NumMyRows; i++) { int curGRID = FullMatrixRowMap().GID(i); if (ReducedMatrixRowMap()->MyGID(curGRID)) { // Check if this row should go into reduced matrix EPETRA_CHK_ERR(GetRowGCIDs(i, NumEntries, Values, Indices)); // Get current row (Indices are global) int ierr = ReducedMatrix()->InsertGlobalValues(curGRID, NumEntries, Values, Indices); // Insert into reduce matrix // Positive errors will occur because we are submitting col entries that are not part of // reduced system. However, because we specified a column map to the ReducedMatrix constructor // these extra column entries will be ignored and we will be politely reminded by a positive // error code if (ierr<0) EPETRA_CHK_ERR(ierr); } else { EPETRA_CHK_ERR(GetRow(i, NumEntries, Values, Indices)); // Get current row if (NumEntries==1) { double pivot = Values[0]; if (pivot==0.0) EPETRA_CHK_ERR(-1); // Encountered zero row, unable to continue int indX = Indices[0]; for (j=0; j<NumVectors; j++) (*tempExportX_)[j][indX] = (*FullRHS)[j][i]/pivot; } // Otherwise, this is a singleton column and we will scan for the pivot element needed // for post-solve equations else { int targetCol = ColSingletonColLIDs_[ColSingletonCounter]; for (j=0; j<NumEntries; j++) { if (Indices[j]==targetCol) { double pivot = Values[j]; if (pivot==0.0) EPETRA_CHK_ERR(-2); // Encountered zero column, unable to continue ColSingletonPivotLIDs_[ColSingletonCounter] = j; // Save for later use ColSingletonPivots_[ColSingletonCounter] = pivot; ColSingletonCounter++; break; } } } } } // Now convert to local indexing. We have constructed things so that the domain and range of the // matrix will have the same map. If the reduced matrix domain and range maps were not the same, the // differences were addressed in the ConstructRedistributeExporter() method EPETRA_CHK_ERR(ReducedMatrix()->FillComplete(*ReducedMatrixDomainMap(), *ReducedMatrixRangeMap())); // Construct Reduced LHS (Puts any initial guess values into reduced system) ReducedLHS_ = new Epetra_MultiVector(*ReducedMatrixDomainMap(), NumVectors); EPETRA_CHK_ERR(ReducedLHS_->Import(*FullLHS, *Full2ReducedLHSImporter_, Insert)); FullLHS->PutScalar(0.0); // zero out Full LHS since we will inject values as we get them // Construct Reduced RHS // First compute influence of already-known values of X on RHS tempX_ = new Epetra_MultiVector(FullMatrixDomainMap(), NumVectors); tempB_ = new Epetra_MultiVector(FullRHS->Map(), NumVectors); //Inject known X values into tempX for purpose of computing tempB = FullMatrix*tempX // Also inject into full X since we already know the solution if (FullMatrix()->RowMatrixImporter()!=0) { EPETRA_CHK_ERR(tempX_->Export(*tempExportX_, *FullMatrix()->RowMatrixImporter(), Add)); EPETRA_CHK_ERR(FullLHS->Export(*tempExportX_, *FullMatrix()->RowMatrixImporter(), Add)); } else { tempX_->Update(1.0, *tempExportX_, 0.0); FullLHS->Update(1.0, *tempExportX_, 0.0); } EPETRA_CHK_ERR(FullMatrix()->Multiply(false, *tempX_, *tempB_)); EPETRA_CHK_ERR(tempB_->Update(1.0, *FullRHS, -1.0)); // tempB now has influence of already-known X values ReducedRHS_ = new Epetra_MultiVector(*ReducedMatrixRowMap(), FullRHS->NumVectors()); EPETRA_CHK_ERR(ReducedRHS_->Import(*tempB_, *Full2ReducedRHSImporter_, Insert)); // Finally construct Reduced Linear Problem ReducedProblem_ = new Epetra_LinearProblem(ReducedMatrix_, ReducedLHS_, ReducedRHS_); double fn = FullMatrix()->NumGlobalRows(); double fnnz = FullMatrix()->NumGlobalNonzeros(); double rn = ReducedMatrix()->NumGlobalRows(); double rnnz = ReducedMatrix()->NumGlobalNonzeros(); RatioOfDimensions_ = rn/fn; RatioOfNonzeros_ = rnnz/fnnz; HaveReducedProblem_ = true; return(0); }
// ================================================ ====== ==== ==== == = //! Apply the preconditioner to an Epetra_MultiVector X, puts the result in Y int ML_Epetra::FaceMatrixFreePreconditioner::ApplyInverse(const Epetra_MultiVector& B_, Epetra_MultiVector& X) const{ const Epetra_MultiVector *B; Epetra_MultiVector *Bcopy=0; /* Sanity Checks */ int NumVectors=B_.NumVectors(); if (!B_.Map().SameAs(*FaceDomainMap_)) ML_CHK_ERR(-1); if (NumVectors != X.NumVectors()) ML_CHK_ERR(-1); Epetra_MultiVector r_edge(*FaceDomainMap_,NumVectors,false); Epetra_MultiVector e_edge(*FaceDomainMap_,NumVectors,false); Epetra_MultiVector e_node(*CoarseMap_,NumVectors,false); Epetra_MultiVector r_node(*CoarseMap_,NumVectors,false); /* Deal with the B==X case */ if (B_.Pointers()[0] == X.Pointers()[0]){ Bcopy=new Epetra_MultiVector(B_); B=Bcopy; X.PutScalar(0.0); } else B=&B_; for(int i=0;i<num_cycles;i++){ /* Pre-smoothing */ #ifdef HAVE_ML_IFPACK if(Smoother_) ML_CHK_ERR(Smoother_->ApplyInverse(*B,X)); #endif if(MaxLevels > 0){ if(i != 0 #ifdef HAVE_ML_IFPACK || Smoother_ #endif ){ /* Calculate Residual (r_e = b - (S+M+Addon) * x) */ ML_CHK_ERR(Operator_->Apply(X,r_edge)); ML_CHK_ERR(r_edge.Update(1.0,*B,-1.0)); /* Xfer to coarse grid (r_n = P' * r_e) */ ML_CHK_ERR(Prolongator_->Multiply(true,r_edge,r_node)); } else{ /* Xfer to coarse grid (r_n = P' * r_e) */ ML_CHK_ERR(Prolongator_->Multiply(true,*B,r_node)); } /* AMG on coarse grid (e_n = (CoarseMatrix)^{-1} r_n) */ ML_CHK_ERR(CoarsePC->ApplyInverse(r_node,e_node)); /* Xfer back to fine grid (e_e = P * e_n) */ ML_CHK_ERR(Prolongator_->Multiply(false,e_node,e_edge)); /* Add in correction (x = x + e_e) */ ML_CHK_ERR(X.Update(1.0,e_edge,1.0)); }/*end if*/ /* Post-Smoothing */ #ifdef HAVE_ML_IFPACK if(Smoother_) ML_CHK_ERR(Smoother_->ApplyInverse(*B,X)); #endif }/*end for*/ /* Cleanup */ if(Bcopy) delete Bcopy; return 0; }/*end ApplyInverse*/
// // Amesos_TestMultiSolver.cpp reads in a matrix in Harwell-Boeing format, // calls one of the sparse direct solvers, using blocked right hand sides // and computes the error and residual. // // TestSolver ignores the Harwell-Boeing right hand sides, creating // random right hand sides instead. // // Amesos_TestMultiSolver can test either A x = b or A^T x = b. // This can be a bit confusing because sparse direct solvers // use compressed column storage - the transpose of Trilinos' // sparse row storage. // // Matrices: // readA - Serial. As read from the file. // transposeA - Serial. The transpose of readA. // serialA - if (transpose) then transposeA else readA // distributedA - readA distributed to all processes // passA - if ( distributed ) then distributedA else serialA // // int Amesos_TestMultiSolver( Epetra_Comm &Comm, char *matrix_file, int numsolves, SparseSolverType SparseSolver, bool transpose, int special, AMESOS_MatrixType matrix_type ) { int iam = Comm.MyPID() ; // int hatever; // if ( iam == 0 ) std::cin >> hatever ; Comm.Barrier(); Epetra_Map * readMap; Epetra_CrsMatrix * readA; Epetra_Vector * readx; Epetra_Vector * readb; Epetra_Vector * readxexact; std::string FileName = matrix_file ; int FN_Size = FileName.size() ; std::string LastFiveBytes = FileName.substr( EPETRA_MAX(0,FN_Size-5), FN_Size ); std::string LastFourBytes = FileName.substr( EPETRA_MAX(0,FN_Size-4), FN_Size ); bool NonContiguousMap = false; if ( LastFiveBytes == ".triU" ) { NonContiguousMap = true; // Call routine to read in unsymmetric Triplet matrix EPETRA_CHK_ERR( Trilinos_Util_ReadTriples2Epetra( matrix_file, false, Comm, readMap, readA, readx, readb, readxexact, NonContiguousMap ) ); } else { if ( LastFiveBytes == ".triS" ) { NonContiguousMap = true; // Call routine to read in symmetric Triplet matrix EPETRA_CHK_ERR( Trilinos_Util_ReadTriples2Epetra( matrix_file, true, Comm, readMap, readA, readx, readb, readxexact, NonContiguousMap ) ); } else { if ( LastFourBytes == ".mtx" ) { EPETRA_CHK_ERR( Trilinos_Util_ReadMatrixMarket2Epetra( matrix_file, Comm, readMap, readA, readx, readb, readxexact) ); } else { // Call routine to read in HB problem Trilinos_Util_ReadHb2Epetra( matrix_file, Comm, readMap, readA, readx, readb, readxexact) ; } } } Epetra_CrsMatrix transposeA(Copy, *readMap, 0); Epetra_CrsMatrix *serialA ; if ( transpose ) { assert( CrsMatrixTranspose( readA, &transposeA ) == 0 ); serialA = &transposeA ; } else { serialA = readA ; } // Create uniform distributed map Epetra_Map map(readMap->NumGlobalElements(), 0, Comm); Epetra_Map* map_; if( NonContiguousMap ) { // // map gives us NumMyElements and MyFirstElement; // int NumGlobalElements = readMap->NumGlobalElements(); int NumMyElements = map.NumMyElements(); int MyFirstElement = map.MinMyGID(); std::vector<int> MapMap_( NumGlobalElements ); readMap->MyGlobalElements( &MapMap_[0] ) ; Comm.Broadcast( &MapMap_[0], NumGlobalElements, 0 ) ; map_ = new Epetra_Map( NumGlobalElements, NumMyElements, &MapMap_[MyFirstElement], 0, Comm); } else { map_ = new Epetra_Map( map ) ; } // Create Exporter to distribute read-in matrix and vectors Epetra_Export exporter(*readMap, *map_); Epetra_CrsMatrix A(Copy, *map_, 0); Epetra_RowMatrix * passA = 0; Epetra_MultiVector * passx = 0; Epetra_MultiVector * passb = 0; Epetra_MultiVector * passxexact = 0; Epetra_MultiVector * passresid = 0; Epetra_MultiVector * passtmp = 0; Epetra_MultiVector x(*map_,numsolves); Epetra_MultiVector b(*map_,numsolves); Epetra_MultiVector xexact(*map_,numsolves); Epetra_MultiVector resid(*map_,numsolves); Epetra_MultiVector tmp(*map_,numsolves); Epetra_MultiVector serialx(*readMap,numsolves); Epetra_MultiVector serialb(*readMap,numsolves); Epetra_MultiVector serialxexact(*readMap,numsolves); Epetra_MultiVector serialresid(*readMap,numsolves); Epetra_MultiVector serialtmp(*readMap,numsolves); bool distribute_matrix = ( matrix_type == AMESOS_Distributed ) ; if ( distribute_matrix ) { // // Initialize x, b and xexact to the values read in from the file // A.Export(*serialA, exporter, Add); Comm.Barrier(); assert(A.FillComplete()==0); Comm.Barrier(); passA = &A; passx = &x; passb = &b; passxexact = &xexact; passresid = &resid; passtmp = &tmp; } else { passA = serialA; passx = &serialx; passb = &serialb; passxexact = &serialxexact; passresid = &serialresid; passtmp = &serialtmp; } passxexact->SetSeed(131) ; passxexact->Random(); passx->SetSeed(11231) ; passx->Random(); passb->PutScalar( 0.0 ); passA->Multiply( transpose, *passxexact, *passb ) ; Epetra_MultiVector CopyB( *passb ) ; double Anorm = passA->NormInf() ; SparseDirectTimingVars::SS_Result.Set_Anorm(Anorm) ; Epetra_LinearProblem Problem( (Epetra_RowMatrix *) passA, (Epetra_MultiVector *) passx, (Epetra_MultiVector *) passb ); double max_resid = 0.0; for ( int j = 0 ; j < special+1 ; j++ ) { Epetra_Time TotalTime( Comm ) ; if ( false ) { #ifdef TEST_UMFPACK unused code } else if ( SparseSolver == UMFPACK ) { UmfpackOO umfpack( (Epetra_RowMatrix *) passA, (Epetra_MultiVector *) passx, (Epetra_MultiVector *) passb ) ; umfpack.SetTrans( transpose ) ; umfpack.Solve() ; #endif #ifdef TEST_SUPERLU } else if ( SparseSolver == SuperLU ) { SuperluserialOO superluserial( (Epetra_RowMatrix *) passA, (Epetra_MultiVector *) passx, (Epetra_MultiVector *) passb ) ; superluserial.SetPermc( SuperLU_permc ) ; superluserial.SetTrans( transpose ) ; superluserial.SetUseDGSSV( special == 0 ) ; superluserial.Solve() ; #endif #ifdef HAVE_AMESOS_SLUD } else if ( SparseSolver == SuperLUdist ) { SuperludistOO superludist( Problem ) ; superludist.SetTrans( transpose ) ; EPETRA_CHK_ERR( superludist.Solve( true ) ) ; #endif #ifdef HAVE_AMESOS_SLUD2 } else if ( SparseSolver == SuperLUdist2 ) { Superludist2_OO superludist2( Problem ) ; superludist2.SetTrans( transpose ) ; EPETRA_CHK_ERR( superludist2.Solve( true ) ) ; #endif #ifdef TEST_SPOOLES } else if ( SparseSolver == SPOOLES ) { SpoolesOO spooles( (Epetra_RowMatrix *) passA, (Epetra_MultiVector *) passx, (Epetra_MultiVector *) passb ) ; spooles.SetTrans( transpose ) ; spooles.Solve() ; #endif #ifdef HAVE_AMESOS_DSCPACK } else if ( SparseSolver == DSCPACK ) { Teuchos::ParameterList ParamList ; Amesos_Dscpack dscpack( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( dscpack.SetParameters( ParamList ) ); EPETRA_CHK_ERR( dscpack.Solve( ) ); #endif #ifdef HAVE_AMESOS_UMFPACK } else if ( SparseSolver == UMFPACK ) { Teuchos::ParameterList ParamList ; Amesos_Umfpack umfpack( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( umfpack.SetParameters( ParamList ) ); EPETRA_CHK_ERR( umfpack.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( umfpack.Solve( ) ); #endif #ifdef HAVE_AMESOS_KLU } else if ( SparseSolver == KLU ) { Teuchos::ParameterList ParamList ; Amesos_Klu klu( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( klu.SetParameters( ParamList ) ); EPETRA_CHK_ERR( klu.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( klu.SymbolicFactorization( ) ); EPETRA_CHK_ERR( klu.NumericFactorization( ) ); EPETRA_CHK_ERR( klu.Solve( ) ); #endif #ifdef HAVE_AMESOS_PARAKLETE } else if ( SparseSolver == PARAKLETE ) { Teuchos::ParameterList ParamList ; Amesos_Paraklete paraklete( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( paraklete.SetParameters( ParamList ) ); EPETRA_CHK_ERR( paraklete.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( paraklete.SymbolicFactorization( ) ); EPETRA_CHK_ERR( paraklete.NumericFactorization( ) ); EPETRA_CHK_ERR( paraklete.Solve( ) ); #endif #ifdef HAVE_AMESOS_SLUS } else if ( SparseSolver == SuperLU ) { Epetra_SLU superluserial( &Problem ) ; EPETRA_CHK_ERR( superluserial.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( superluserial.SymbolicFactorization( ) ); EPETRA_CHK_ERR( superluserial.NumericFactorization( ) ); EPETRA_CHK_ERR( superluserial.Solve( ) ); #endif #ifdef HAVE_AMESOS_LAPACK } else if ( SparseSolver == LAPACK ) { Teuchos::ParameterList ParamList ; ParamList.set( "MaxProcs", -3 ); Amesos_Lapack lapack( Problem ) ; EPETRA_CHK_ERR( lapack.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( lapack.SymbolicFactorization( ) ); EPETRA_CHK_ERR( lapack.NumericFactorization( ) ); EPETRA_CHK_ERR( lapack.Solve( ) ); #endif #ifdef HAVE_AMESOS_TAUCS } else if ( SparseSolver == TAUCS ) { Teuchos::ParameterList ParamList ; Amesos_Taucs taucs( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( taucs.SetParameters( ParamList ) ); EPETRA_CHK_ERR( taucs.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( taucs.SymbolicFactorization( ) ); EPETRA_CHK_ERR( taucs.NumericFactorization( ) ); EPETRA_CHK_ERR( taucs.Solve( ) ); #endif #ifdef HAVE_AMESOS_PARDISO } else if ( SparseSolver == PARDISO ) { Teuchos::ParameterList ParamList ; Amesos_Pardiso pardiso( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( pardiso.SetParameters( ParamList ) ); EPETRA_CHK_ERR( pardiso.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( pardiso.SymbolicFactorization( ) ); EPETRA_CHK_ERR( pardiso.NumericFactorization( ) ); EPETRA_CHK_ERR( pardiso.Solve( ) ); #endif #ifdef HAVE_AMESOS_PARKLETE } else if ( SparseSolver == PARKLETE ) { Teuchos::ParameterList ParamList ; Amesos_Parklete parklete( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( parklete.SetParameters( ParamList ) ); EPETRA_CHK_ERR( parklete.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( parklete.SymbolicFactorization( ) ); EPETRA_CHK_ERR( parklete.NumericFactorization( ) ); EPETRA_CHK_ERR( parklete.Solve( ) ); #endif #ifdef HAVE_AMESOS_MUMPS } else if ( SparseSolver == MUMPS ) { Teuchos::ParameterList ParamList ; Amesos_Mumps mumps( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( mumps.SetParameters( ParamList ) ); EPETRA_CHK_ERR( mumps.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( mumps.SymbolicFactorization( ) ); EPETRA_CHK_ERR( mumps.NumericFactorization( ) ); EPETRA_CHK_ERR( mumps.Solve( ) ); #endif #ifdef HAVE_AMESOS_SCALAPACK } else if ( SparseSolver == SCALAPACK ) { Teuchos::ParameterList ParamList ; Amesos_Scalapack scalapack( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( scalapack.SetParameters( ParamList ) ); EPETRA_CHK_ERR( scalapack.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( scalapack.SymbolicFactorization( ) ); EPETRA_CHK_ERR( scalapack.NumericFactorization( ) ); EPETRA_CHK_ERR( scalapack.Solve( ) ); #endif #ifdef HAVE_AMESOS_SUPERLUDIST } else if ( SparseSolver == SUPERLUDIST ) { Teuchos::ParameterList ParamList ; Amesos_Superludist superludist( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( superludist.SetParameters( ParamList ) ); EPETRA_CHK_ERR( superludist.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( superludist.SymbolicFactorization( ) ); EPETRA_CHK_ERR( superludist.NumericFactorization( ) ); EPETRA_CHK_ERR( superludist.Solve( ) ); #endif #ifdef HAVE_AMESOS_SUPERLU } else if ( SparseSolver == SUPERLU ) { Teuchos::ParameterList ParamList ; Amesos_Superlu superlu( Problem ) ; ParamList.set( "MaxProcs", -3 ); EPETRA_CHK_ERR( superlu.SetParameters( ParamList ) ); EPETRA_CHK_ERR( superlu.SetUseTranspose( transpose ) ); EPETRA_CHK_ERR( superlu.SymbolicFactorization( ) ); EPETRA_CHK_ERR( superlu.NumericFactorization( ) ); EPETRA_CHK_ERR( superlu.Solve( ) ); #endif #ifdef TEST_SPOOLESSERIAL } else if ( SparseSolver == SPOOLESSERIAL ) { SpoolesserialOO spoolesserial( (Epetra_RowMatrix *) passA, (Epetra_MultiVector *) passx, (Epetra_MultiVector *) passb ) ; spoolesserial.Solve() ; #endif } else { SparseDirectTimingVars::log_file << "Solver not implemented yet" << std::endl ; std::cerr << "\n\n#################### Requested solver not available (Or not tested with blocked RHS) on this platform #####################\n" << std::endl ; } SparseDirectTimingVars::SS_Result.Set_Total_Time( TotalTime.ElapsedTime() ); // SparseDirectTimingVars::SS_Result.Set_First_Time( 0.0 ); // SparseDirectTimingVars::SS_Result.Set_Middle_Time( 0.0 ); // SparseDirectTimingVars::SS_Result.Set_Last_Time( 0.0 ); // // Compute the error = norm(xcomp - xexact ) // std::vector <double> error(numsolves) ; double max_error = 0.0; passresid->Update(1.0, *passx, -1.0, *passxexact, 0.0); passresid->Norm2(&error[0]); for ( int i = 0 ; i< numsolves; i++ ) if ( error[i] > max_error ) max_error = error[i] ; SparseDirectTimingVars::SS_Result.Set_Error(max_error) ; // passxexact->Norm2(&error[0] ) ; // passx->Norm2(&error ) ; // // Compute the residual = norm(Ax - b) // std::vector <double> residual(numsolves) ; passtmp->PutScalar(0.0); passA->Multiply( transpose, *passx, *passtmp); passresid->Update(1.0, *passtmp, -1.0, *passb, 0.0); // passresid->Update(1.0, *passtmp, -1.0, CopyB, 0.0); passresid->Norm2(&residual[0]); for ( int i = 0 ; i< numsolves; i++ ) if ( residual[i] > max_resid ) max_resid = residual[i] ; SparseDirectTimingVars::SS_Result.Set_Residual(max_resid) ; std::vector <double> bnorm(numsolves); passb->Norm2( &bnorm[0] ) ; SparseDirectTimingVars::SS_Result.Set_Bnorm(bnorm[0]) ; std::vector <double> xnorm(numsolves); passx->Norm2( &xnorm[0] ) ; SparseDirectTimingVars::SS_Result.Set_Xnorm(xnorm[0]) ; if ( false && iam == 0 ) { std::cout << " Amesos_TestMutliSolver.cpp " << std::endl ; for ( int i = 0 ; i< numsolves && i < 10 ; i++ ) { std::cout << "i=" << i << " error = " << error[i] << " xnorm = " << xnorm[i] << " residual = " << residual[i] << " bnorm = " << bnorm[i] << std::endl ; } std::cout << std::endl << " max_resid = " << max_resid ; std::cout << " max_error = " << max_error << std::endl ; std::cout << " Get_residual() again = " << SparseDirectTimingVars::SS_Result.Get_Residual() << std::endl ; } } delete readA; delete readx; delete readb; delete readxexact; delete readMap; delete map_; Comm.Barrier(); return 0 ; }
int ShyLU_Probing_Operator::Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const { #ifdef TIMING_OUTPUT apply_time_->start(); #endif int nvectors = X.NumVectors(); bool local = (C_->Comm().NumProc() == 1); int err; //cout << "No of colors after probing" << nvectors << endl; #ifdef TIMING_OUTPUT matvec_time_->start(); #endif err = G_->Multiply(false, X, *temp2); assert(err == 0); if (!local) err = C_->Multiply(false, X, *temp); else { // localize X double *values; int mylda; X.ExtractView(&values, &mylda); Epetra_SerialComm LComm; // Use Serial Comm for the local blocks. Epetra_Map SerialMap(X.Map().NumMyElements(), X.Map().NumMyElements(), X.Map().MyGlobalElements(), 0, LComm); Epetra_MultiVector Xl(View, SerialMap, values, mylda, X.NumVectors()); err = C_->Multiply(false, Xl, *temp); } assert(err == 0); #ifdef TIMING_OUTPUT matvec_time_->stop(); #endif int nrows = C_->RowMap().NumMyElements(); #ifdef DEBUG cout << "DEBUG MODE" << endl; assert(nrows == localDRowMap_->NumGlobalElements()); int gids[nrows], gids1[nrows]; C_->RowMap().MyGlobalElements(gids); localDRowMap_->MyGlobalElements(gids1); for (int i = 0; i < nrows; i++) { assert(gids[i] == gids1[i]); } #endif #ifdef TIMING_OUTPUT localize_time_->start(); #endif //int err; int lda; double *values; if (!local) { err = temp->ExtractView(&values, &lda); assert (err == 0); // copy to local vector //TODO: OMP parallel assert(lda == nrows); //#pragma omp parallel for shared(nvectors, nrows, values) for (int v = 0; v < nvectors; v++) { for (int i = 0; i < nrows; i++) { err = ltemp->ReplaceMyValue(i, v, values[i+v*lda]); assert (err == 0); } } } #ifdef TIMING_OUTPUT localize_time_->stop(); trisolve_time_->start(); #endif if (!local) { LP_->SetRHS(ltemp.getRawPtr()); } else { //LP_->SetRHS(temp.getRawPtr()); } //LP_->SetLHS(localX.getRawPtr()); //TODO: Why not just in Reset(). Check the distr path. ssym_->OrigLP->SetLHS(localX.getRawPtr()); ssym_->OrigLP->SetRHS(temp.getRawPtr()); ssym_->ReIdx_LP->fwd(); solver_->Solve(); #ifdef TIMING_OUTPUT trisolve_time_->stop(); dist_time_->start(); #endif if (!local) { err = localX->ExtractView(&values, &lda); assert (err == 0); //Copy back to dist vector //TODO: OMP parallel //#pragma omp parallel for for (int v = 0; v < nvectors; v++) { for (int i = 0; i < nrows; i++) { err = temp->ReplaceMyValue(i, v, values[i+v*lda]); assert (err == 0); } } } #ifdef TIMING_OUTPUT dist_time_->stop(); matvec2_time_->start(); #endif if (!local) { R_->Multiply(false, *temp, Y); } else { // Should Y be localY in Multiply and then exported to Y ?? TODO: // Use view mode ? double *values; int mylda; Y.ExtractView(&values, &mylda); Epetra_SerialComm LComm; // Use Serial Comm for the local blocks. Epetra_Map SerialMap(Y.Map().NumMyElements(), Y.Map().NumMyElements(), Y.Map().MyGlobalElements(), 0, LComm); Epetra_MultiVector Yl(View, SerialMap, values, mylda, Y.NumVectors()); R_->Multiply(false, *localX, Yl); } #ifdef TIMING_OUTPUT matvec2_time_->stop(); update_time_->start(); #endif err = Y.Update(1.0, *temp2, -1.0); //cout << Y.MyLength() << " " << temp2.MyLength() << endl; assert(err == 0); #ifdef TIMING_OUTPUT update_time_->stop(); apply_time_->stop(); #endif cntApply++; 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); }
int main(int argc, char *argv[]) { #ifdef HAVE_MPI Teuchos::GlobalMPISession mpiSession(&argc, &argv, 0); Epetra_MpiComm Comm(MPI_COMM_WORLD); #else Epetra_SerialComm Comm; #endif int nProcs, myPID ; Teuchos::ParameterList pLUList ; // ParaLU parameters Teuchos::ParameterList isoList ; // Isorropia parameters Teuchos::ParameterList shyLUList ; // shyLU parameters Teuchos::ParameterList ifpackList ; // shyLU parameters string ipFileName = "ShyLU.xml"; // TODO : Accept as i/p nProcs = mpiSession.getNProc(); myPID = Comm.MyPID(); if (myPID == 0) { cout <<"Parallel execution: nProcs="<< nProcs << endl; } // =================== Read input xml file ============================= Teuchos::updateParametersFromXmlFile(ipFileName, &pLUList); isoList = pLUList.sublist("Isorropia Input"); shyLUList = pLUList.sublist("ShyLU Input"); shyLUList.set("Outer Solver Library", "AztecOO"); // Get matrix market file name string MMFileName = Teuchos::getParameter<string>(pLUList, "mm_file"); string prec_type = Teuchos::getParameter<string>(pLUList, "preconditioner"); int maxiters = Teuchos::getParameter<int>(pLUList, "Outer Solver MaxIters"); double tol = Teuchos::getParameter<double>(pLUList, "Outer Solver Tolerance"); string rhsFileName = pLUList.get<string>("rhs_file", ""); if (myPID == 0) { cout << "Input :" << endl; cout << "ParaLU params " << endl; pLUList.print(std::cout, 2, true, true); cout << "Matrix market file name: " << MMFileName << endl; } // ==================== Read input Matrix ============================== Epetra_CrsMatrix *A; Epetra_MultiVector *b1; int err = EpetraExt::MatrixMarketFileToCrsMatrix(MMFileName.c_str(), Comm, A); //EpetraExt::MatlabFileToCrsMatrix(MMFileName.c_str(), Comm, A); //assert(err != 0); //cout <<"Done reading the matrix"<< endl; int n = A->NumGlobalRows(); //cout <<"n="<< n << endl; // Create input vectors Epetra_Map vecMap(n, 0, Comm); if (rhsFileName != "") { err = EpetraExt::MatrixMarketFileToMultiVector(rhsFileName.c_str(), vecMap, b1); } else { b1 = new Epetra_MultiVector(vecMap, 1, false); b1->PutScalar(1.0); } Epetra_MultiVector x(vecMap, 1); //cout << "Created the vectors" << endl; // Partition the matrix with hypergraph partitioning and redisstribute Isorropia::Epetra::Partitioner *partitioner = new Isorropia::Epetra::Partitioner(A, isoList, false); partitioner->partition(); Isorropia::Epetra::Redistributor rd(partitioner); Epetra_CrsMatrix *newA; Epetra_MultiVector *newX, *newB; rd.redistribute(*A, newA); delete A; A = newA; rd.redistribute(x, newX); rd.redistribute(*b1, newB); Epetra_LinearProblem problem(A, newX, newB); AztecOO solver(problem); ifpackList ; Ifpack_Preconditioner *prec; ML_Epetra::MultiLevelPreconditioner *MLprec; if (prec_type.compare("ShyLU") == 0) { prec = new Ifpack_ShyLU(A); prec->SetParameters(shyLUList); prec->Initialize(); prec->Compute(); //(dynamic_cast<Ifpack_ShyLU *>(prec))->JustTryIt(); //cout << " Going to set it in solver" << endl ; solver.SetPrecOperator(prec); //cout << " Done setting the solver" << endl ; } else if (prec_type.compare("ILU") == 0) { ifpackList.set( "fact: level-of-fill", 1 ); prec = new Ifpack_ILU(A); prec->SetParameters(ifpackList); prec->Initialize(); prec->Compute(); solver.SetPrecOperator(prec); } else if (prec_type.compare("ILUT") == 0) { ifpackList.set( "fact: ilut level-of-fill", 2 ); ifpackList.set( "fact: drop tolerance", 1e-8); prec = new Ifpack_ILUT(A); prec->SetParameters(ifpackList); prec->Initialize(); prec->Compute(); solver.SetPrecOperator(prec); } else if (prec_type.compare("ML") == 0) { Teuchos::ParameterList mlList; // TODO : Take it from i/p MLprec = new ML_Epetra::MultiLevelPreconditioner(*A, mlList, true); solver.SetPrecOperator(MLprec); } solver.SetAztecOption(AZ_solver, AZ_gmres); solver.SetMatrixName(333); //solver.SetAztecOption(AZ_output, 1); //solver.SetAztecOption(AZ_conv, AZ_Anorm); //cout << "Going to iterate for the global problem" << endl; solver.Iterate(maxiters, tol); // compute ||Ax - b|| double Norm; Epetra_MultiVector Ax(vecMap, 1); Epetra_MultiVector *newAx; rd.redistribute(Ax, newAx); A->Multiply(false, *newX, *newAx); newAx->Update(1.0, *newB, -1.0); newAx->Norm2(&Norm); double ANorm = A->NormOne(); cout << "|Ax-b |/|A| = " << Norm/ANorm << endl; delete newAx; if (prec_type.compare("ML") == 0) { delete MLprec; } else { delete prec; } delete b1; delete newX; delete newB; delete A; delete partitioner; }
// ============================================================================ int ML_Epetra::MatrixFreePreconditioner:: ApplyInverse(const Epetra_MultiVector& B, Epetra_MultiVector& X) const { ResetStartTime(); if (!X.Map().SameAs(R_->OperatorDomainMap())) ML_CHK_ERR(-1); if (X.NumVectors() != B.NumVectors()) ML_CHK_ERR(-1); Epetra_MultiVector B_c(R_->OperatorRangeMap(), B.NumVectors()); Epetra_MultiVector X_c(R_->OperatorRangeMap(), B.NumVectors()); if (PrecType_ == ML_MFP_PRESMOOTHER_ONLY) { ML_CHK_ERR(ApplyPreSmoother(X)); } else if (PrecType_ == ML_MFP_ADDITIVE) { // ================================= // // ADDITIVE TWO-LEVEL PRECONDITIONER // // ================================= // Epetra_MultiVector tmp(B.Map(), B.NumVectors()); ML_CHK_ERR(R_->Multiply(false, B, B_c)); ML_CHK_ERR(MLP_->ApplyInverse(B_c, X_c)); ML_CHK_ERR(R_->Multiply(true, X_c, tmp)); // apply smoother with zero starting solution ML_CHK_ERR(ApplyPreSmoother(X)); // sum up the two contributions ML_CHK_ERR(X.Update(1.0, tmp, 1.0)); } else if (PrecType_ == ML_MFP_HYBRID) { // =============================== // // HYBRID TWO-LEVEL PRECONDITIONER // // =============================== // Epetra_MultiVector tmp(B.Map(), B.NumVectors()); Epetra_MultiVector sol(B.Map(), B.NumVectors()); sol = B; // apply pre-smoother ML_CHK_ERR(ApplyPreSmoother(sol)); // new residual ML_CHK_ERR(Operator_.Apply(sol, tmp)); ML_CHK_ERR(tmp.Update(1.0, B, -1.0)); // restrict to coarse ML_CHK_ERR(R_->Multiply(false, tmp, B_c)); X_c.PutScalar(0.0); // solve coarse problem ML_CHK_ERR(MLP_->ApplyInverse(B_c, X_c)); // prolongate back ML_CHK_ERR(R_->Multiply(true, X_c, tmp)); // add to solution, X now has the correction ML_CHK_ERR(sol.Update(1.0, tmp, 1.0)); // apply post-smoother /////ML_CHK_ERR(PostSmoother_->ApplyInverse(B, sol)); ML_CHK_ERR(ApplyPostSmoother(sol, B, tmp)); X = sol; } else ML_CHK_ERR(-3); // type not recognized AddAndResetStartTime("ApplyInverse()"); return(0); }