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 CSysSolve::MultiGrid_LinSolver(CSysMatrix **Jacobian, CSysVector **LinSysRes, CSysVector **LinSysSol, CMatrixVectorProduct & mat_vec, CGeometry **geometry, CConfig *config, unsigned short iMesh, unsigned short mu, double tol, unsigned long m, bool monitoring) { CSysVector A_x(*LinSysRes[iMesh]); CSysVector ResAux(*LinSysRes[iMesh]); CSysVector SolAux(*LinSysSol[iMesh]); unsigned short Smoother = config->GetKind_Linear_Solver_Prec(); /*--- Smooth the solution in the fine grid Jac_h Sol_h = Res_h, because the implementation (assumes that the initial guess is 0)... it is only possible to perform one smoothing ---*/ switch (Smoother) { case LU_SGS: Jacobian[iMesh]->ComputeLU_SGSPreconditioner(*LinSysRes[iMesh], *LinSysSol[iMesh], geometry[iMesh], config); break; case JACOBI: Jacobian[iMesh]->BuildJacobiPreconditioner(); Jacobian[iMesh]->ComputeJacobiPreconditioner(*LinSysRes[iMesh], *LinSysSol[iMesh], geometry[iMesh], config); break; case ILU: Jacobian[iMesh]->BuildILUPreconditioner(); Jacobian[iMesh]->ComputeILUPreconditioner(*LinSysRes[iMesh], *LinSysSol[iMesh], geometry[iMesh], config); break; case LINELET: Jacobian[iMesh]->BuildJacobiPreconditioner(); Jacobian[iMesh]->ComputeLineletPreconditioner(*LinSysRes[iMesh], *LinSysSol[iMesh], geometry[iMesh], config); break; } if (iMesh < config->GetMGLevels()) { /*--- Compute the residual in the finesh grid ResAux_h = Jac_h.Sol_h - Res_h ---*/ Jacobian[iMesh]->MatrixVectorProduct(*LinSysSol[iMesh], A_x, geometry[iMesh], config); ResAux -= A_x; /*--- Restrict the residual to the coarse grid Res_H = I^H_h.ResAux_h ---*/ SetRestricted_Residual(&ResAux, LinSysRes[iMesh+1], geometry[iMesh+1], config); /*--- Recursive call to MultiGrid_Cycle ---*/ for (unsigned short imu = 0; imu <= mu; imu++) { if (iMesh == config->GetMGLevels()-2) MultiGrid_LinSolver(Jacobian, LinSysRes, LinSysSol, mat_vec, geometry, config, iMesh+1, 0, tol, m, monitoring); else MultiGrid_LinSolver(Jacobian, LinSysRes, LinSysSol, mat_vec, geometry, config, iMesh+1, mu, tol, m, monitoring); } /*--- Prolongate solution to the fine grid solution SolAux_h = I^h_H.Sol_H ---*/ SetProlongated_Solution(&SolAux, LinSysSol[iMesh+1], geometry[iMesh+1], config); /*--- Update the fine grid solution Sol_h += SolAux_h ---*/ *LinSysSol[iMesh] += config->GetDamp_Correc_Prolong()*SolAux; } }