Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_BiCGStab.H
Go to the documentation of this file.
1#ifndef AMREX_BICGSTAB_H_
2#define AMREX_BICGSTAB_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_BLProfiler.H>
6#include <AMReX_Math.H>
7#include <AMReX_Print.H>
8
9#include <cmath>
10#include <iomanip>
11#include <limits>
12
13namespace amrex {
14
22template <typename V, typename M>
24{
25public:
26
27 using RT = typename M::RT; // double or float
28
29 BiCGStab () = default;
30
34 void define (M& linop) { m_linop = &linop; }
35
49 void solve (V& a_sol, V const& a_rhs, RT a_tol_rel, RT a_tol_abs, int a_its=-1);
50
53 void setInitialGuessNonzero (bool flag) { m_nonzero_guess = flag; }
54
56 void setVerbose (int v) { m_verbose = v; }
57
59 void setMaxIters (int niters) { m_maxiter = niters; }
60
62 [[nodiscard]] int getNumIters () const { return m_its; }
63
71 [[nodiscard]] int getStatus () const { return m_status; }
72
74 [[nodiscard]] RT getResidualNorm () const { return m_res; }
75
77 [[nodiscard]] RT getInitialResidualNorm () const { return m_rnorm0; }
78
79private:
80
81 int m_verbose = 0;
82 bool m_nonzero_guess = false;
83 int m_maxiter = 2000;
84 int m_its = 0;
85 int m_status = -1;
86 RT m_res = std::numeric_limits<RT>::max();
87 RT m_rnorm0 = std::numeric_limits<RT>::max();
88 RT m_rtol = RT(0);
89 RT m_atol = RT(0);
90
91 M* m_linop = nullptr;
92};
93
94template <typename V, typename M>
95void BiCGStab<V,M>::solve (V& a_sol, V const& a_rhs, RT a_tol_rel, RT a_tol_abs, int a_its)
96{
97 BL_PROFILE("BiCGStab::solve()");
98
99 AMREX_ALWAYS_ASSERT(m_linop != nullptr);
100
101 m_rtol = a_tol_rel;
102 m_atol = a_tol_abs;
103 if (a_its < 0) { a_its = m_maxiter; }
104
105 m_its = 0;
106 m_status = -1;
107
108 V r = m_linop->makeVecRHS();
109 V rh = m_linop->makeVecRHS();
110 V p = m_linop->makeVecRHS();
111 V ph = m_linop->makeVecLHS();
112 V v = m_linop->makeVecRHS();
113 V sh = m_linop->makeVecLHS();
114 V t = m_linop->makeVecRHS();
115
116 if (m_nonzero_guess) {
117 // r = b - A x. apply() needs an x made by makeVecLHS.
118 m_linop->assign(ph, a_sol);
119 m_linop->apply(v, ph);
120 m_linop->linComb(r, RT(1), a_rhs, RT(-1), v);
121 } else {
122 m_linop->setToZero(a_sol);
123 m_linop->assign(r, a_rhs);
124 }
125 m_linop->assign(rh, r);
126
127 RT rnorm = m_linop->norm2(r);
128 RT const rnorm0 = rnorm;
129 m_res = rnorm;
130 m_rnorm0 = rnorm;
131
132 if (m_verbose > 0) {
133 amrex::Print() << "BiCGStab: Initial residual (error0) = " << rnorm0 << '\n';
134 }
135
136 if (rnorm0 == RT(0) || rnorm0 < m_atol) {
137 m_status = 0;
138 return;
139 }
140
141 RT rho_1 = RT(0), alpha = RT(0), omega = RT(0);
142
143 auto converged = [&] (RT rn) {
144 return rn == RT(0) || rn < m_rtol*rnorm0 || rn < m_atol;
145 };
146
147 for (int iter = 1; iter <= a_its; ++iter)
148 {
149 RT const rho = m_linop->dotProduct(rh, r);
150 if (rho == RT(0) || !amrex::isfinite(rho)) { m_status = 2; break; }
151
152 if (iter == 1) {
153 m_linop->assign(p, r);
154 } else {
155 RT const beta = (rho/rho_1)*(alpha/omega);
156 m_linop->increment(p, v, -omega); // p -= omega*v
157 m_linop->scale(p, beta);
158 m_linop->increment(p, r, RT(1)); // p = r + beta*(p - omega*v)
159 }
160
161 m_linop->precond(ph, p);
162 m_linop->apply(v, ph);
163
164 RT const rhv = m_linop->dotProduct(rh, v);
165 if (rhv == RT(0) || !amrex::isfinite(rhv)) { m_status = 3; break; }
166 alpha = rho/rhv;
167
168 m_linop->increment(a_sol, ph, alpha);
169 m_linop->increment(r, v, -alpha); // r is now s
170
171 rnorm = m_linop->norm2(r);
172 m_its = iter;
173 m_res = rnorm;
174
175 if (m_verbose > 1) {
176 amrex::Print() << "BiCGStab: Half Iter " << std::setw(11) << iter
177 << " rel. err. " << rnorm/rnorm0 << '\n';
178 }
179
180 if (converged(rnorm)) { m_status = 0; break; }
181
182 m_linop->precond(sh, r);
183 m_linop->apply(t, sh);
184
185 RT const tt = m_linop->dotProduct(t, t);
186 if (tt == RT(0) || !amrex::isfinite(tt)) { m_status = 4; break; }
187 omega = m_linop->dotProduct(t, r) / tt;
188 if (omega == RT(0) || !amrex::isfinite(omega)) { m_status = 5; break; }
189
190 m_linop->increment(a_sol, sh, omega);
191 m_linop->increment(r, t, -omega);
192
193 rnorm = m_linop->norm2(r);
194 m_res = rnorm;
195
196 if (m_verbose > 1) {
197 amrex::Print() << "BiCGStab: Iteration " << std::setw(11) << iter
198 << " rel. err. " << rnorm/rnorm0 << '\n';
199 }
200
201 if (converged(rnorm)) { m_status = 0; break; }
202
203 rho_1 = rho;
204 }
205
206 if (m_status == -1) { m_status = 1; }
207
208 if (m_verbose > 0) {
209 amrex::Print() << "BiCGStab: Final: Iteration " << std::setw(4) << m_its
210 << " rel. err. " << rnorm/rnorm0 << '\n';
211 }
212
213 if (m_status != 0 && m_verbose > 0) {
214 amrex::Print() << "BiCGStab: Failed to converge, status = " << m_status << '\n';
215 }
216}
217
218}
219
220#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
GpuArray< Real, 3 > beta
Definition AMReX_MLEBNodeFDLaplacian.cpp:1834
BiCGStab solver with right preconditioning.
Definition AMReX_BiCGStab.H:24
typename M::RT RT
Definition AMReX_BiCGStab.H:27
RT getInitialResidualNorm() const
Gets the 2-norm of the initial residual of the last solve().
Definition AMReX_BiCGStab.H:77
BiCGStab()=default
void setInitialGuessNonzero(bool flag)
Definition AMReX_BiCGStab.H:53
int getNumIters() const
Gets the number of iterations.
Definition AMReX_BiCGStab.H:62
void define(M &linop)
Definition AMReX_BiCGStab.H:34
RT getResidualNorm() const
Gets the 2-norm of the residual.
Definition AMReX_BiCGStab.H:74
void setMaxIters(int niters)
Sets the max number of iterations.
Definition AMReX_BiCGStab.H:59
void setVerbose(int v)
Sets verbosity.
Definition AMReX_BiCGStab.H:56
void solve(V &a_sol, V const &a_rhs, RT a_tol_rel, RT a_tol_abs, int a_its=-1)
Solve the linear system.
Definition AMReX_BiCGStab.H:95
int getStatus() const
Gets the solver status.
Definition AMReX_BiCGStab.H:71
This class provides the user with a few print options.
Definition AMReX_Print.H:35
Definition AMReX_Amr.cpp:50