void sLinsysRootAggregation::Dsolve( sData *prob, OoqpVector& rhs ) { StochVector& b = dynamic_cast<StochVector&>(rhs); int myRank; MPI_Comm_rank(mpiComm,&myRank); SimpleVector& b0 = dynamic_cast<SimpleVector&>(*b.vec); if(0==myRank) solveReduced(prob, b0); // broadcast b0 from rank 0 to others MPI_Bcast(b0.elements(), b0.length(), MPI_DOUBLE, 0, mpiComm); }
void sLinsysRoot::Dsolve( sData *prob, OoqpVector& x ) { //#ifdef TIMING // double tTot = MPI_Wtime(); //#endif StochVector& b = dynamic_cast<StochVector&>(x); //! commented - already done in addLnizi - cpetra // for(size_t it=0; it<children.size(); it++) { // children[it]->Dsolve(prob->children[it], *b.children[it]); //} SimpleVector& b0 = dynamic_cast<SimpleVector&>(*b.vec); #ifdef TIMING stochNode->resMon.eDsolve.clear(); stochNode->resMon.recDsolveTmLocal_start(); #endif solveReduced(prob, b0); #ifdef TIMING stochNode->resMon.recDsolveTmLocal_stop(); #endif }
unsigned long CSysSolve::FGMRES(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, CPreconditioner & precond, double tol, unsigned long m, bool monitoring) { int rank = 0; #ifndef NO_MPI #ifdef WINDOWS MPI_Comm_rank(MPI_COMM_WORLD, &rank); #else rank = MPI::COMM_WORLD.Get_rank(); #endif #endif /*--- Check the subspace size ---*/ if (m < 1) { if (rank == 0) cerr << "CSysSolve::FGMRES: illegal value for subspace size, m = " << m << endl; #ifdef NO_MPI exit(1); #else #ifdef WINDOWS MPI_Abort(MPI_COMM_WORLD,1); MPI_Finalize(); #else MPI::COMM_WORLD.Abort(1); MPI::Finalize(); #endif #endif } /*--- Check the subspace size ---*/ if (m > 1000) { if (rank == 0) cerr << "CSysSolve::FGMRES: illegal value for subspace size (too high), m = " << m << endl; #ifdef NO_MPI exit(1); #else #ifdef WINDOWS MPI_Abort(MPI_COMM_WORLD,1); MPI_Finalize(); #else MPI::COMM_WORLD.Abort(1); MPI::Finalize(); #endif #endif } /*--- Define various arrays Note: elements in w and z are initialized to x to avoid creating a temporary CSysVector object for the copy constructor ---*/ vector<CSysVector> w(m+1, x); vector<CSysVector> z(m+1, x); vector<double> g(m+1, 0.0); vector<double> sn(m+1, 0.0); vector<double> cs(m+1, 0.0); vector<double> y(m, 0.0); vector<vector<double> > H(m+1, vector<double>(m, 0.0)); /*--- Calculate the norm of the rhs vector ---*/ double norm0 = b.norm(); /*--- Calculate the initial residual (actually the negative residual) and compute its norm ---*/ mat_vec(x,w[0]); w[0] -= b; double beta = w[0].norm(); if ( (beta < tol*norm0) || (beta < eps) ) { /*--- System is already solved ---*/ if (rank == 0) cout << "CSysSolve::FGMRES(): system solved by initial guess." << endl; return 0; } /*--- Normalize residual to get w_{0} (the negative sign is because w[0] holds the negative residual, as mentioned above) ---*/ w[0] /= -beta; /*--- Initialize the RHS of the reduced system ---*/ g[0] = beta; /*--- Set the norm to the initial residual value ---*/ norm0 = beta; /*--- Output header information including initial residual ---*/ int i = 0; if ((monitoring) && (rank == 0)) { writeHeader("FGMRES", tol, beta); writeHistory(i, beta, norm0); } /*--- Loop over all search directions ---*/ for (i = 0; i < m; i++) { /*--- Check if solution has converged ---*/ if (beta < tol*norm0) break; /*--- Precondition the CSysVector w[i] and store result in z[i] ---*/ precond(w[i], z[i]); /*--- Add to Krylov subspace ---*/ mat_vec(z[i], w[i+1]); /*--- Modified Gram-Schmidt orthogonalization ---*/ modGramSchmidt(i, H, w); /*--- Apply old Givens rotations to new column of the Hessenberg matrix then generate the new Givens rotation matrix and apply it to the last two elements of H[:][i] and g ---*/ for (int k = 0; k < i; k++) applyGivens(sn[k], cs[k], H[k][i], H[k+1][i]); generateGivens(H[i][i], H[i+1][i], sn[i], cs[i]); applyGivens(sn[i], cs[i], g[i], g[i+1]); /*--- Set L2 norm of residual and check if solution has converged ---*/ beta = fabs(g[i+1]); /*--- Output the relative residual if necessary ---*/ if ((((monitoring) && (rank == 0)) && ((i+1) % 100 == 0)) && (rank == 0)) writeHistory(i+1, beta, norm0); } /*--- Solve the least-squares system and update solution ---*/ solveReduced(i, H, g, y); for (int k = 0; k < i; k++) { x.Plus_AX(y[k], z[k]); } if ((monitoring) && (rank == 0)) { cout << "# FGMRES final (true) residual:" << endl; cout << "# Iteration = " << i << ": |res|/|res0| = " << beta/norm0 << endl; } // /*--- Recalculate final (neg.) residual (this should be optional) ---*/ // mat_vec(x, w[0]); // w[0] -= b; // double res = w[0].norm(); // // if (fabs(res - beta) > tol*10) { // if (rank == 0) { // cout << "# WARNING in CSysSolve::FGMRES(): " << endl; // cout << "# true residual norm and calculated residual norm do not agree." << endl; // cout << "# res - beta = " << res - beta << endl; // } // } return i; }
void QpGenStochLinsysRootAugRedPrecond::Dsolve( QpGenStochData *prob, OoqpVector& b_ ) { StochVector& bst = dynamic_cast<StochVector&>(b_); for(int it=0; it<children.size(); it++) { children[it]->Dsolve(prob->children[it], *bst.children[it]); } int n = locnx+locmy; int N=n+locmz; SimpleVector& b = dynamic_cast<SimpleVector&>(*bst.vec); assert(b.length()==N); int rankMe = stochNode->rankMe; int rankPrcnd = stochNode->rankPrcnd; int rankZeroW = stochNode->rankZeroW; int commP2ZeroW = stochNode->commP2ZeroW; /////////////////////////////////////////////////////////////////////// // precond waits to be signaled /////////////////////////////////////////////////////////////////////// if(me==ePrecond) { if(NULL==tmpVec1) tmpVec1 = new double[n+PREC_EXTRA_DOUBLES]; SimpleVector rhs(tmpVec1, n); MPI_Status status; while(true) { MPI_Recv(tmpVec1, n+PREC_EXTRA_DOUBLES, MPI_DOUBLE, rankZeroW, 1, mpiComm, &status); if(tmpVec1[n+PREC_EXTRA_DOUBLES-1]==1) break; solver->solve(rhs); iErr = MPI_Send(&rhs[0], n, MPI_DOUBLE, rankZeroW, 2, mpiComm); assert(iErr==MPI_SUCCESS); } } /////////////////////////////////////////////////////////////////////// // special worker // - signals the precond and waits for Px matVec via BiCGStabSolver // - broadcasts the solution to the other workers /////////////////////////////////////////////////////////////////////// if(me==eSpecialWorker) { if(NULL==tmpVec1) tmpVec1 = new double[n+PREC_EXTRA_DOUBLES]; //allocate the buffer here reuse these buffer in the MatVec Pmult->setTmpVec1(tmpVec1); solveReduced(prob, b); // notify the preconditioner that we converged; // the rest of buffer does not matter. tmpVec1[n+PREC_EXTRA_DOUBLES-1] = 1; MPI_Send(tmpVec1, n+PREC_EXTRA_DOUBLES, MPI_DOUBLE, rankPrcnd, 1, mpiComm); } /////////////////////////////////////////////////////////////////////// // the rest of the workers wait for special worker to converge // and obtain the solution /////////////////////////////////////////////////////////////////////// MPI_Bcast(&b[0], N, MPI_DOUBLE, rankZeroW, mpiComm); //printf("DSolve rank[%d] finished!!!!!!!\n", rankMe); }