/* Simple convenience wrapper for GMRES solver */ static void solve_gmres_bem3d(matrixtype type, void *A, pavector b, pavector x, real accuracy, uint steps) { addeval_t addevalA; pavector rhat, q, tau; pamatrix qr; uint i, j, n, kk, kmax; real norm; addevalA = (addeval_t) addeval_A; kmax = 500; n = b->dim; assert(x->dim == n); qr = new_zero_amatrix(n, kmax); rhat = new_avector(n); q = new_avector(n); tau = new_avector(kmax); clear_avector(x); init_gmres(addevalA, A, b, x, rhat, q, &kk, qr, tau); for (i = 0; i < steps; i += kmax) { for (j = 0; j < kmax && i + j < steps; ++j) { step_gmres(addevalA, A, b, x, rhat, q, &kk, qr, tau); norm = residualnorm_gmres(rhat, kk); #ifndef NDEBUG printf(" Residual: %.5e\t Iterations: %u\r", norm, j + i); fflush(stdout); #endif if (norm <= accuracy) { finish_gmres(addevalA, A, b, x, rhat, q, &kk, qr, tau); break; } } if (norm <= accuracy) { break; } else { finish_gmres(addevalA, A, b, x, rhat, q, &kk, qr, tau); } } printf("\n"); del_avector(rhat); del_avector(q); del_avector(tau); del_amatrix(qr); }
int gmres(spinor * const P,spinor * const Q, const int m, const int max_restarts, const double eps_sq, const int rel_prec, const int N, const int parallel, matrix_mult f){ int restart, i, j, k; double beta, eps, norm; complex tmp1, tmp2; spinor ** solver_field = NULL; const int nr_sf = 3; if(N == VOLUME) { init_solver_field(&solver_field, VOLUMEPLUSRAND, nr_sf); } else { init_solver_field(&solver_field, VOLUMEPLUSRAND/2, nr_sf); } eps=sqrt(eps_sq); init_gmres(m, VOLUMEPLUSRAND); norm = sqrt(square_norm(Q, N, parallel)); assign(solver_field[2], P, N); for(restart = 0; restart < max_restarts; restart++){ /* r_0=Q-AP (b=Q, x+0=P) */ f(solver_field[0], solver_field[2]); diff(solver_field[0], Q, solver_field[0], N); /* v_0=r_0/||r_0|| */ alpha[0].re=sqrt(square_norm(solver_field[0], N, parallel)); if(g_proc_id == g_stdio_proc && g_debug_level > 1){ printf("%d\t%g true residue\n", restart*m, alpha[0].re*alpha[0].re); fflush(stdout); } if(alpha[0].re==0.){ assign(P, solver_field[2], N); finalize_solver(solver_field, nr_sf); return(restart*m); } mul_r(V[0], 1./alpha[0].re, solver_field[0], N); for(j = 0; j < m; j++){ /* solver_field[0]=A*v_j */ f(solver_field[0], V[j]); /* Set h_ij and omega_j */ /* solver_field[1] <- omega_j */ assign(solver_field[1], solver_field[0], N); for(i = 0; i <= j; i++){ H[i][j] = scalar_prod(V[i], solver_field[1], N, parallel); assign_diff_mul(solver_field[1], V[i], H[i][j], N); } _complex_set(H[j+1][j], sqrt(square_norm(solver_field[1], N, parallel)), 0.); for(i = 0; i < j; i++){ tmp1 = H[i][j]; tmp2 = H[i+1][j]; _mult_real(H[i][j], tmp2, s[i]); _add_assign_complex_conj(H[i][j], c[i], tmp1); _mult_real(H[i+1][j], tmp1, s[i]); _diff_assign_complex(H[i+1][j], c[i], tmp2); } /* Set beta, s, c, alpha[j],[j+1] */ beta = sqrt(_complex_square_norm(H[j][j]) + _complex_square_norm(H[j+1][j])); s[j] = H[j+1][j].re / beta; _mult_real(c[j], H[j][j], 1./beta); _complex_set(H[j][j], beta, 0.); _mult_real(alpha[j+1], alpha[j], s[j]); tmp1 = alpha[j]; _mult_assign_complex_conj(alpha[j], c[j], tmp1); /* precision reached? */ if(g_proc_id == g_stdio_proc && g_debug_level > 1){ printf("%d\t%g residue\n", restart*m+j, alpha[j+1].re*alpha[j+1].re); fflush(stdout); } if(((alpha[j+1].re <= eps) && (rel_prec == 0)) || ((alpha[j+1].re <= eps*norm) && (rel_prec == 1))){ _mult_real(alpha[j], alpha[j], 1./H[j][j].re); assign_add_mul(solver_field[2], V[j], alpha[j], N); for(i = j-1; i >= 0; i--){ for(k = i+1; k <= j; k++){ _mult_assign_complex(tmp1, H[i][k], alpha[k]); _diff_complex(alpha[i], tmp1); } _mult_real(alpha[i], alpha[i], 1./H[i][i].re); assign_add_mul(solver_field[2], V[i], alpha[i], N); } for(i = 0; i < m; i++){ alpha[i].im = 0.; } assign(P, solver_field[2], N); finalize_solver(solver_field, nr_sf); return(restart*m+j); } /* if not */ else{ if(j != m-1){ mul_r(V[(j+1)], 1./H[j+1][j].re, solver_field[1], N); } } } j=m-1; /* prepare for restart */ _mult_real(alpha[j], alpha[j], 1./H[j][j].re); assign_add_mul(solver_field[2], V[j], alpha[j], N); for(i = j-1; i >= 0; i--){ for(k = i+1; k <= j; k++){ _mult_assign_complex(tmp1, H[i][k], alpha[k]); _diff_complex(alpha[i], tmp1); } _mult_real(alpha[i], alpha[i], 1./H[i][i].re); assign_add_mul(solver_field[2], V[i], alpha[i], N); } for(i = 0; i < m; i++){ alpha[i].im = 0.; } } /* If maximal number of restarts is reached */ assign(P, solver_field[2], N); finalize_solver(solver_field, nr_sf); return(-1); }