int bicgstab(const LinearOperator& A, HilbertSpaceX& x, const HilbertSpaceB& b, const Preconditioner& M, Iteration& iter) { typedef typename mtl::Collection<HilbertSpaceX>::value_type Scalar; typedef HilbertSpaceX Vector; Scalar rho_1(0), rho_2(0), alpha(0), beta(0), gamma, omega(0); Vector p(size(x)), phat(size(x)), s(size(x)), shat(size(x)), t(size(x)), v(size(x)), r(size(x)), rtilde(size(x)); r = b - A * x; rtilde = r; while (! iter.finished(r)) { rho_1 = dot(rtilde, r); MTL_THROW_IF(rho_1 == 0.0, unexpected_orthogonality()); if (iter.first()) p = r; else { MTL_THROW_IF(omega == 0.0, unexpected_orthogonality()); beta = (rho_1 / rho_2) * (alpha / omega); p = r + beta * (p - omega * v); } phat = solve(M, p); v = A * phat; gamma = dot(rtilde, v); MTL_THROW_IF(gamma == 0.0, unexpected_orthogonality()); alpha = rho_1 / gamma; s = r - alpha * v; if (iter.finished(s)) { x += alpha * phat; break; } shat = solve(M, s); t = A * shat; omega = dot(t, s) / dot(t, t); x += omega * shat + alpha * phat; r = s - omega * t; rho_2 = rho_1; ++iter; } return iter; }
unsigned long CSysSolve::BCGSTAB_LinSolver(const CSysVector & b, CSysVector & x, CMatrixVectorProduct & mat_vec, CPreconditioner & precond, su2double tol, unsigned long m, su2double *residual, bool monitoring) { int rank = 0; #ifdef HAVE_MPI MPI_Comm_rank(MPI_COMM_WORLD, &rank); #endif /*--- Check the subspace size ---*/ if (m < 1) { if (rank == MASTER_NODE) cerr << "CSysSolve::BCGSTAB: illegal value for subspace size, m = " << m << endl; #ifndef HAVE_MPI exit(EXIT_FAILURE); #else MPI_Abort(MPI_COMM_WORLD,1); MPI_Finalize(); #endif } CSysVector r(b); CSysVector r_0(b); CSysVector p(b); CSysVector v(b); CSysVector s(b); CSysVector t(b); CSysVector phat(b); CSysVector shat(b); CSysVector A_x(b); /*--- Calculate the initial residual, compute norm, and check if system is already solved ---*/ mat_vec(x, A_x); r -= A_x; r_0 = r; // recall, r holds b initially su2double norm_r = r.norm(); su2double norm0 = b.norm(); if ( (norm_r < tol*norm0) || (norm_r < eps) ) { if (rank == MASTER_NODE) cout << "CSysSolve::BCGSTAB(): system solved by initial guess." << endl; return 0; } /*--- Initialization ---*/ su2double alpha = 1.0, beta = 1.0, omega = 1.0, rho = 1.0, rho_prime = 1.0; /*--- Set the norm to the initial initial residual value ---*/ norm0 = norm_r; /*--- Output header information including initial residual ---*/ int i = 0; if ((monitoring) && (rank == MASTER_NODE)) { WriteHeader("BCGSTAB", tol, norm_r); WriteHistory(i, norm_r, norm0); } /*--- Loop over all search directions ---*/ for (i = 0; i < (int)m; i++) { /*--- Compute rho_prime ---*/ rho_prime = rho; /*--- Compute rho_i ---*/ rho = dotProd(r, r_0); /*--- Compute beta ---*/ beta = (rho / rho_prime) * (alpha /omega); /*--- p_{i} = r_{i-1} + beta * p_{i-1} - beta * omega * v_{i-1} ---*/ su2double beta_omega = -beta*omega; p.Equals_AX_Plus_BY(beta, p, beta_omega, v); p.Plus_AX(1.0, r); /*--- Preconditioning step ---*/ precond(p, phat); mat_vec(phat, v); /*--- Calculate step-length alpha ---*/ su2double r_0_v = dotProd(r_0, v); alpha = rho / r_0_v; /*--- s_{i} = r_{i-1} - alpha * v_{i} ---*/ s.Equals_AX_Plus_BY(1.0, r, -alpha, v); /*--- Preconditioning step ---*/ precond(s, shat); mat_vec(shat, t); /*--- Calculate step-length omega ---*/ omega = dotProd(t, s) / dotProd(t, t); /*--- Update solution and residual: ---*/ x.Plus_AX(alpha, phat); x.Plus_AX(omega, shat); r.Equals_AX_Plus_BY(1.0, s, -omega, t); /*--- Check if solution has converged, else output the relative residual if necessary ---*/ norm_r = r.norm(); if (norm_r < tol*norm0) break; if (((monitoring) && (rank == MASTER_NODE)) && ((i+1) % 50 == 0) && (rank == MASTER_NODE)) WriteHistory(i+1, norm_r, norm0); } if ((monitoring) && (rank == MASTER_NODE)) { cout << "# BCGSTAB final (true) residual:" << endl; cout << "# Iteration = " << i << ": |res|/|res0| = " << norm_r/norm0 << ".\n" << endl; } // /*--- Recalculate final residual (this should be optional) ---*/ // mat_vec(x, A_x); // r = b; r -= A_x; // su2double true_res = r.norm(); // // if ((fabs(true_res - norm_r) > tol*10.0) && (rank == MASTER_NODE)) { // cout << "# WARNING in CSysSolve::BCGSTAB(): " << endl; // cout << "# true residual norm and calculated residual norm do not agree." << endl; // cout << "# true_res - calc_res = " << true_res <<" "<< norm_r << endl; // } (*residual) = norm_r; return i; }
void BiCGSTAB(Epetra_CrsMatrix &A, Epetra_Vector &x, Epetra_Vector &b, Ifpack_CrsRiluk *M, int Maxiter, double Tolerance, double *residual, bool verbose) { // Allocate vectors needed for iterations Epetra_Vector phat(x.Map()); phat.SetFlopCounter(x); Epetra_Vector p(x.Map()); p.SetFlopCounter(x); Epetra_Vector shat(x.Map()); shat.SetFlopCounter(x); Epetra_Vector s(x.Map()); s.SetFlopCounter(x); Epetra_Vector r(x.Map()); r.SetFlopCounter(x); Epetra_Vector rtilde(x.Map()); rtilde.Random(); rtilde.SetFlopCounter(x); Epetra_Vector v(x.Map()); v.SetFlopCounter(x); A.Multiply(false, x, r); // r = A*x r.Update(1.0, b, -1.0); // r = b - A*x double r_norm, b_norm, scaled_r_norm, rhon, rhonm1 = 1.0; double alpha = 1.0, omega = 1.0, sigma; double omega_num, omega_den; r.Norm2(&r_norm); b.Norm2(&b_norm); scaled_r_norm = r_norm/b_norm; r.Dot(rtilde,&rhon); if (verbose) cout << "Initial residual = " << r_norm << " Scaled residual = " << scaled_r_norm << endl; for (int i=0; i<Maxiter; i++) { // Main iteration loop double beta = (rhon/rhonm1) * (alpha/omega); rhonm1 = rhon; /* p = r + beta*(p - omega*v) */ /* phat = M^-1 p */ /* v = A phat */ double dtemp = - beta*omega; p.Update(1.0, r, dtemp, v, beta); if (M==0) phat.Scale(1.0, p); else M->Solve(false, p, phat); A.Multiply(false, phat, v); rtilde.Dot(v,&sigma); alpha = rhon/sigma; /* s = r - alpha*v */ /* shat = M^-1 s */ /* r = A shat (r is a tmp here for t ) */ s.Update(-alpha, v, 1.0, r, 0.0); if (M==0) shat.Scale(1.0, s); else M->Solve(false, s, shat); A.Multiply(false, shat, r); r.Dot(s, &omega_num); r.Dot(r, &omega_den); omega = omega_num / omega_den; /* x = x + alpha*phat + omega*shat */ /* r = s - omega*r */ x.Update(alpha, phat, omega, shat, 1.0); r.Update(1.0, s, -omega); r.Norm2(&r_norm); scaled_r_norm = r_norm/b_norm; r.Dot(rtilde,&rhon); if (verbose) cout << "Iter "<< i << " residual = " << r_norm << " Scaled residual = " << scaled_r_norm << endl; if (scaled_r_norm < Tolerance) break; } return; }