114 void solve (V& a_sol, V
const& a_rhs,
RT a_tol_rel,
RT a_tol_abs,
int a_its=-1);
137 [[nodiscard]]
int getStatus ()
const {
return m_status; }
144 void allocate_scratch ();
145 void cycle (V& a_xx,
int& a_status,
int& a_itcount,
RT& a_rnorm0);
146 void build_solution (V& a_xx,
int it);
147 void compute_residual (V& a_rr, V
const& a_xx, V
const& a_bb);
149 bool converged (
RT r0,
RT r)
const;
151 void gram_schmidt_orthogonalization (
int it);
152 void update_hessenberg (
int it,
bool happyend,
RT& res);
155 int m_maxiter = 2000;
158 int m_restrtlen = 30;
159 RT m_res = std::numeric_limits<RT>::max();
169 std::unique_ptr<V> m_v_tmp_rhs;
170 std::unique_ptr<V> m_v_tmp_lhs;
172 M* m_linop =
nullptr;
175template <
typename V,
typename M>
181template <
typename V,
typename M>
184 int rs = m_restrtlen;
186 m_hh_1d.resize(std::size_t(rs + 2) * (rs + 1));
187 m_hh =
Table2D<RT>(m_hh_1d.data(), {0,0}, {rs+1,rs});
189 m_hes_1d.resize(std::size_t(rs + 2) * (rs + 1));
190 m_hes =
Table2D<RT>(m_hes_1d.data(), {0,0}, {rs+1,rs});
192 m_grs.resize(rs + 2);
197template <
typename V,
typename M>
200 if (m_restrtlen != rl) {
207template <
typename V,
typename M>
214template <
typename V,
typename M>
219 m_res = std::numeric_limits<RT>::max();
226template <
typename V,
typename M>
227bool GMRES<V,M>::converged (RT r0, RT r)
const
229 return (r < r0*m_rtol) || (r < m_atol);
232template <
typename V,
typename M>
241 if (m_v_tmp_rhs ==
nullptr) {
242 m_v_tmp_rhs = std::make_unique<V>(m_linop->makeVecRHS());
244 if (m_v_tmp_lhs ==
nullptr) {
245 m_v_tmp_lhs = std::make_unique<V>(m_linop->makeVecLHS());
248 m_vv.reserve(m_restrtlen+1);
249 for (
int i = 0; i < 2; ++i) {
250 m_vv.emplace_back(m_linop->makeVecRHS());
257 if (a_its < 0) { a_its = m_maxiter; }
261 m_linop->assign(m_vv[0], a_rhs);
262 m_linop->setToZero(a_sol);
266 cycle(a_sol, m_status, m_its, rnorm0);
268 while (m_status == -1 && m_its < a_its) {
269 compute_residual(m_vv[0], a_sol, a_rhs);
270 cycle(a_sol, m_status, m_its, rnorm0);
273 if (m_status == -1 && m_its >= a_its) { m_status = 1; }
281 amrex::Print() <<
"GMRES: Solve Time = " << t1-t0 <<
'\n';
285template <
typename V,
typename M>
290 m_res = m_linop->norm2(m_vv[0]);
293 if (m_res == RT(0.0)) {
298 m_linop->scale(m_vv[0], RT(1.0)/m_res);
300 if (a_itcount == 0) { a_rnorm0 = m_res; }
302 a_status = converged(a_rnorm0,m_res) ? 0 : -1;
305 while (it < m_restrtlen && a_itcount < m_maxiter)
309 <<
", residual = " << m_res <<
", " << m_res/a_rnorm0
313 if (a_status == 0) {
break; }
315 while (m_vv.size() < it+2) {
316 m_vv.emplace_back(m_linop->makeVecRHS());
319 auto const& vv_it = m_vv[it ];
320 auto & vv_it1 = m_vv[it+1];
322 m_linop->precond(*m_v_tmp_lhs, vv_it);
323 m_linop->apply(vv_it1, *m_v_tmp_lhs);
325 gram_schmidt_orthogonalization(it);
327 auto tt = m_linop->norm2(vv_it1);
329 auto const sml = RT((
sizeof(RT) == 8) ? 1.e-99 : 1.e-30);
330 bool happyend = (tt < sml);
332 m_linop->scale(vv_it1, RT(1.0)/tt);
338 update_hessenberg(it, happyend, m_res);
342 a_status = converged(a_rnorm0, m_res) ? 0 : -1;
343 if (happyend) {
break; }
346 if ((m_verbose > 1) && (a_status != 0 || a_itcount >= m_maxiter)) {
348 <<
", residual = " << m_res <<
", " << m_res/a_rnorm0
352 build_solution(a_xx, it-1);
355template <
typename V,
typename M>
356void GMRES<V,M>::gram_schmidt_orthogonalization (
int const it)
362 auto& vv_1 = m_vv[it+1];
364 Vector<RT> lhh(it+1);
366 for (
int j = 0; j <= it; ++j) {
367 m_hh (j,it) = RT(0.0);
368 m_hes(j,it) = RT(0.0);
371 for (
int ncnt = 0; ncnt < 2 ; ++ncnt)
373 for (
int j = 0; j <= it; ++j) {
374 lhh[j] = m_linop->dotProduct(vv_1, m_vv[j]);
377 for (
int j = 0; j <= it; ++j) {
378 m_linop->increment(vv_1, m_vv[j], -lhh[j]);
379 m_hh (j,it) += lhh[j];
380 m_hes(j,it) -= lhh[j];
385template <
typename V,
typename M>
386void GMRES<V,M>::update_hessenberg (
int it,
bool happyend, RT& res)
390 for (
int j = 1; j <= it; ++j) {
391 auto tt = m_hh(j-1,it);
392 m_hh(j-1,it) = m_cc[j-1] * tt + m_ss[j-1] * m_hh(j,it);
393 m_hh(j ,it) = m_cc[j-1] * m_hh(j,it) - m_ss[j-1] * tt;
398 auto tt = std::sqrt(m_hh(it,it)*m_hh(it,it) + m_hh(it+1,it)*m_hh(it+1,it));
399 m_cc[it] = m_hh(it ,it) / tt;
400 m_ss[it] = m_hh(it+1,it) / tt;
401 m_grs[it+1] = - (m_ss[it] * m_grs[it]);
402 m_grs[it ] = m_cc[it] * m_grs[it];
403 m_hh(it,it) = m_cc[it] * m_hh(it,it) + m_ss[it] * m_hh(it+1,it);
404 res = std::abs(m_grs[it+1]);
412template <
typename V,
typename M>
413void GMRES<V,M>::build_solution (V& a_xx,
int const it)
417 if (it < 0) {
return; }
419 if (m_hh(it,it) != RT(0.0)) {
420 m_grs[it] /= m_hh(it,it);
425 for (
int ii = 1; ii <= it; ++ii) {
428 for (
int j = k+1; j <= it; ++j) {
429 tt -= m_hh(k,j) * m_grs[j];
431 m_grs[k] = tt / m_hh(k,k);
434 m_linop->setToZero(*m_v_tmp_rhs);
435 for (
int ii = 0; ii < it+1; ++ii) {
436 m_linop->increment(*m_v_tmp_rhs, m_vv[ii], m_grs[ii]);
439 m_linop->precond(*m_v_tmp_lhs, *m_v_tmp_rhs);
440 m_linop->increment(a_xx, *m_v_tmp_lhs, RT(1.0));
443template <
typename V,
typename M>
444void GMRES<V,M>::compute_residual (V& a_rr, V
const& a_xx, V
const& a_bb)
447 m_linop->assign(*m_v_tmp_lhs, a_xx);
448 m_linop->apply(*m_v_tmp_rhs, *m_v_tmp_lhs);
449 m_linop->linComb(a_rr, RT(1.0), a_bb, RT(-1.0), *m_v_tmp_rhs);