unsigned long CSysSolve::FGMRES_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::FGMRES: illegal value for subspace size, m = " << m << endl; #ifndef HAVE_MPI exit(EXIT_FAILURE); #else MPI_Abort(MPI_COMM_WORLD,1); MPI_Finalize(); #endif } /*--- Check the subspace size ---*/ if (m > 1000) { if (rank == MASTER_NODE) cerr << "CSysSolve::FGMRES: illegal value for subspace size (too high), m = " << m << endl; #ifndef HAVE_MPI exit(EXIT_FAILURE); #else MPI_Abort(MPI_COMM_WORLD,1); MPI_Finalize(); #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<su2double> g(m+1, 0.0); vector<su2double> sn(m+1, 0.0); vector<su2double> cs(m+1, 0.0); vector<su2double> y(m, 0.0); vector<vector<su2double> > H(m+1, vector<su2double>(m, 0.0)); /*--- Calculate the norm of the rhs vector ---*/ su2double norm0 = b.norm(); /*--- Calculate the initial residual (actually the negative residual) and compute its norm ---*/ mat_vec(x, w[0]); w[0] -= b; su2double beta = w[0].norm(); if ( (beta < tol*norm0) || (beta < eps) ) { /*--- System is already solved ---*/ if (rank == MASTER_NODE) 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 == MASTER_NODE)) { WriteHeader("FGMRES", tol, beta); WriteHistory(i, beta, norm0); } /*--- Loop over all search directions ---*/ for (i = 0; i < (int)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 == MASTER_NODE)) && ((i+1) % 50 == 0)) && (rank == MASTER_NODE)) 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 == MASTER_NODE)) { cout << "# FGMRES final (true) residual:" << endl; cout << "# Iteration = " << i << ": |res|/|res0| = " << beta/norm0 << ".\n" << endl; } // /*--- Recalculate final (neg.) residual (this should be optional) ---*/ // mat_vec(x, w[0]); // w[0] -= b; // su2double res = w[0].norm(); // // if (fabs(res - beta) > tol*10) { // if (rank == MASTER_NODE) { // cout << "# WARNING in CSysSolve::FGMRES(): " << endl; // cout << "# true residual norm and calculated residual norm do not agree." << endl; // cout << "# res - beta = " << res - beta << endl; // } // } (*residual) = beta; return i; }
Matrix DivideAndSolve(Matrix A,int p) { double a,b,d,e,s,c,mu,i; int h,j,k,l,m,o,rowstartt,colstartt,rowendt,colendt; Vector v,u,x,y,z; Matrix B,C,D,E,Q,U,H; U = newIdMatrix(); H = newMatrix(); v = newVector(); i = p+1; rowstartt = i; colstartt = 0; while (rowstartt<n) { rowendt = (rowstartt+i-1<n-1)?rowstartt+i-1:n-1; colstartt = rowstartt-i; colendt = colstartt+i-1; /* Now T_i has dimension (p-h)x(p-h) */ /* First zero all but row 1 in T_i */ for (m=colstartt;m<=colendt;m++) { if (norm(A,m,rowstartt,rowendt)!=0.0) { /* Find Householder(A(h:p,m)) */ House(A,v,m,rowstartt,rowendt); for (o=0;o<rowstartt;o++) v[o]=0.0; for (o=rowendt+1;o<n;o++) v[o]=0.0; ApplyHouse(A,v,rowstartt,rowendt); } printf("m=%i, rowstart=%i, rowend=%i\n",m,rowstartt,rowendt); printVector(v); printMatrix(A); } /* Now zero all but the last entry in row 1 */ WeirdHouse(A,v,rowstartt,colstartt,colendt); /* Apply the HouseHolder */ ApplyHouse(A,v,colstartt,colendt); /* Now T_i has one single non-zero entry */ /* Iterate with explicit shift to zero the last non-zero entry */ while (A[rowstartt][colendt]> (A[rowstartt-1][colendt]-A[rowstartt][colendt+1])*epsilon) { printMatrix(A); /* Wilkonson Shift?? */ d =(A[rowstartt-1][colendt]-A[rowstartt][colendt+1])/2.0; b = A[rowstartt][colendt]; mu = A[rowstartt][colendt+1]+d-sign(d)*sqrt(d*d+b*b); /* Determine the givens */ Givens(A[rowstartt-1][colendt]-mu, A[rowstartt][colendt],&s,&c); /* Apply the givens */ ApplyGivens(A,s,c,rowstartt-1,rowstartt,0,n-1); printf("%e\n",A[colstartt][colendt]); } rowstartt+=i; colstartt+=i; } }