Bridge++  Ver. 1.3.x
solver_BiCGStab_DS_L_Cmplx.cpp
Go to the documentation of this file.
1 
15 
16 
17 
18 #ifdef USE_FACTORY
19 namespace {
20  Solver *create_object(Fopr *fopr)
21  {
22  return new Solver_BiCGStab_DS_L_Cmplx(fopr);
23  }
24 
25 
26  bool init = Solver::Factory::Register("BiCGStab_DS_L_Cmplx", create_object);
27 }
28 #endif
29 
30 //- parameter entries
31 namespace {
32  void append_entry(Parameters& param)
33  {
34  param.Register_int("maximum_number_of_iteration", 0);
35  param.Register_double("convergence_criterion_squared", 0.0);
36 
37  param.Register_int("number_of_orthonormal_vectors", 0);
38  param.Register_double("tolerance_for_DynamicSelection_of_L", 0);
39 
40  param.Register_string("verbose_level", "NULL");
41  }
42 
43 
44 #ifdef USE_PARAMETERS_FACTORY
45  bool init_param = ParametersFactory::Register("Solver.BiCGStab_DS_L_Cmplx", append_entry);
46 #endif
47 }
48 //- end
49 
50 //- parameters class
52 //- end
53 
54 const std::string Solver_BiCGStab_DS_L_Cmplx::class_name = "Solver_BiCGStab_DS_L_Cmplx";
55 
56 //====================================================================
58 {
59  const string str_vlevel = params.get_string("verbose_level");
60 
61  m_vl = vout.set_verbose_level(str_vlevel);
62 
63  //- fetch and check input parameters
64  int Niter;
65  double Stop_cond;
66  int N_L;
67  double Tol_L;
68 
69  int err = 0;
70  err += params.fetch_int("maximum_number_of_iteration", Niter);
71  err += params.fetch_double("convergence_criterion_squared", Stop_cond);
72  err += params.fetch_int("number_of_orthonormal_vectors", N_L);
73  err += params.fetch_double("tolerance_for_DynamicSelection_of_L", Tol_L);
74 
75  if (err) {
76  vout.crucial(m_vl, "%s: fetch error, input parameter not found.\n", class_name.c_str());
77  exit(EXIT_FAILURE);
78  }
79 
80 
81  set_parameters(Niter, Stop_cond);
82  set_parameters_DS_L(N_L, Tol_L);
83 }
84 
85 
86 //====================================================================
87 void Solver_BiCGStab_DS_L_Cmplx::set_parameters(const int Niter, const double Stop_cond)
88 {
90 
91  //- print input parameters
92  vout.general(m_vl, "%s: input parameters\n", class_name.c_str());
93  vout.general(m_vl, " Niter = %d\n", Niter);
94  vout.general(m_vl, " Stop_cond = %16.8e\n", Stop_cond);
95 
96  //- range check
97  int err = 0;
98  err += ParameterCheck::non_negative(Niter);
99  err += ParameterCheck::square_non_zero(Stop_cond);
100 
101  if (err) {
102  vout.crucial(m_vl, "%s: parameter range check failed.\n", class_name.c_str());
103  exit(EXIT_FAILURE);
104  }
105 
106  //- store values
107  m_Niter = Niter;
108  m_Stop_cond = Stop_cond;
109 }
110 
111 
112 //====================================================================
113 void Solver_BiCGStab_DS_L_Cmplx::set_parameters_DS_L(const int N_L, const double Tol_L)
114 {
115  //- print input parameters
116  vout.general(m_vl, " N_L = %d\n", N_L);
117  vout.general(m_vl, " Tol_L = %16.8e\n", Tol_L);
118 
119  //- range check
120  int err = 0;
121  err += ParameterCheck::non_negative(N_L);
122  err += ParameterCheck::square_non_zero(Tol_L);
123 
124  if (err) {
125  vout.crucial(m_vl, "%s: parameter range check failed.\n", class_name.c_str());
126  exit(EXIT_FAILURE);
127  }
128 
129  //- store values
130  m_N_L = N_L;
131  m_Tol_L = Tol_L;
132 }
133 
134 
135 //====================================================================
137  int& Nconv, double& diff)
138 {
139  double bnorm2 = b.norm2();
140  double snorm = 1.0 / bnorm2;
141  int bsize = b.size();
142  double rr;
143 
144  vout.paranoiac(m_vl, "%s: starts\n", class_name.c_str());
145  vout.paranoiac(m_vl, " norm of b = %16.8e\n", bnorm2);
146  vout.paranoiac(m_vl, " size of b = %d\n", bsize);
147 
148  reset_field(b);
149 
150 
151  // Nconv = -1;
152  int Nconv2 = 0;
153  copy(s, b); // s = b;
154 
155  solve_init(b, rr);
156 
157  bool is_converged = false;
158 
159  vout.detailed(m_vl, " iter: %8d %22.15e\n", 0, rr * snorm);
160 
161 
162  for (int iter = 0; iter < m_Niter; iter++) {
163  if (is_converged) break;
164 
165  solve_step(rr);
166 
167  Nconv2 += 2 * N_L_prev;
168 
169  vout.detailed(m_vl, " iter,N_L: %8d %8d\n", Nconv2, N_L_prev);
170  vout.detailed(m_vl, " iter: %8d %22.15e\n", Nconv2, rr * snorm);
171 
172  if (rr * snorm < m_Stop_cond) {
173  m_fopr->mult(s, x); // s = m_fopr->mult(x);
174  axpy(s, -1.0, b); // s -= b;
175 
176  double diff2 = s.norm2();
177 
178  if (diff2 * snorm < m_Stop_cond) {
179  // NB. Nconv is calculated above.
180  is_converged = true;
181  } else {
182  copy(s, x); // s = x;
183  solve_init(b, rr);
184  }
185  }
186  }
187 
188  m_fopr->mult(s, x); // s = m_fopr->mult(x);
189  axpy(s, -1.0, b); // s -= b;
190 
191  copy(xq, x); // xq = x;
192 
193  double diff2 = s.norm2();
194 
195  if (diff2 * snorm > m_Stop_cond) {
196  vout.crucial(m_vl, "%s: not converged.\n", class_name.c_str());
197  exit(EXIT_FAILURE);
198  }
199 
200 #pragma omp barrier
201 #pragma omp master
202  {
203  diff = sqrt(diff2);
204  Nconv = Nconv2;
205  }
206 #pragma omp barrier
207 }
208 
209 
210 //====================================================================
212 {
213 #pragma omp barrier
214 #pragma omp master
215  {
216  int Nin = b.nin();
217  int Nvol = b.nvol();
218  int Nex = b.nex();
219 
220  if ((s.nin() != Nin) || (s.nvol() != Nvol) || (s.nex() != Nex)) {
221  s.reset(Nin, Nvol, Nex);
222  x.reset(Nin, Nvol, Nex);
223  r_init.reset(Nin, Nvol, Nex);
224  v_tmp.reset(Nin, Nvol, Nex);
225  }
226 
227  u.resize(m_N_L + 1);
228  r.resize(m_N_L + 1);
229 
230  for (int i = 0; i < m_N_L + 1; ++i) {
231  u[i].reset(Nin, Nvol, Nex);
232  r[i].reset(Nin, Nvol, Nex);
233  }
234  }
235 #pragma omp barrier
236 
237  vout.paranoiac(m_vl, "%s: field size reset.\n", class_name.c_str());
238 }
239 
240 
241 //====================================================================
243 {
244  copy(x, s); // x = s;
245 
246  //- r[0] = b - A x_0
247  m_fopr->mult(v_tmp, s); // v_tmp = m_fopr->mult(s);
248  copy(r[0], b); // r[0] = b;
249  axpy(r[0], -1.0, v_tmp); // r[0] -= v_tmp;
250 
251  copy(r_init, r[0]); // r_init = r[0];
252  rr = r[0].norm2(); // rr = r[0] * r[0];
253 
254  u[0].set(0.0); // u[0] = 0.0;
255 
256 #pragma omp barrier
257 #pragma omp master
258  {
259  rho_prev = cmplx(-1.0, 0.0);
260 
261  // NB. alpha_prev = 0.0 \neq 1.0
262  alpha_prev = cmplx(0.0, 0.0);
263 
264  N_L_prev = m_N_L;
265  }
266 #pragma omp barrier
267 }
268 
269 
270 //====================================================================
272 {
273  dcomplex rho_prev2 = rho_prev;
274  dcomplex alpha_prev2 = alpha_prev;
275 
276  int N_L_tmp = 0; // superficial initialization
277  dcomplex c_Rayleigh_prev = cmplx(0.0, 0.0);
278 
279  bool is_converged_L = false;
280 
281 
282  for (int j = 0; j < N_L_prev; ++j) {
283  if (!is_converged_L) {
284  dcomplex rho = dotc(r[j], r_init); // rho = r[j] * r_init;
285  rho = conj(rho);
286 
287  dcomplex beta = alpha_prev2 * (rho / rho_prev2);
288 
289  rho_prev2 = rho;
290 
291  for (int i = 0; i < j + 1; ++i) {
292  aypx(-beta, u[i], r[i]); // u[i] = - beta * u[i] + r[i];
293  }
294 
295  m_fopr->mult(u[j + 1], u[j]); // u[j+1] = m_fopr->mult(u[j]);
296 
297  dcomplex gamma = dotc(u[j + 1], r_init);
298  alpha_prev2 = rho_prev2 / conj(gamma);
299 
300  for (int i = 0; i < j + 1; ++i) {
301  axpy(r[i], -alpha_prev2, u[i + 1]); // r[i] -= alpha_prev * u[i+1];
302  }
303 
304  m_fopr->mult(r[j + 1], r[j]); // r[j+1] = m_fopr->mult(r[j]);
305 
306  axpy(x, alpha_prev2, u[0]); // x += alpha_prev * u[0];
307 
308 
309  //- calculate the Rayleigh quotient for N_L_tmp
310 
311  // dcomplex c_Rayleigh = (r[j] * r[j+1]) / (r[j] * r[j]);
312  double r_tmp = r[j].norm2(); // r_tmp = r[j] * r[j];
313  dcomplex c_Rayleigh = dotc(r[j], r[j + 1]) / r_tmp; // c_Rayleigh = r[j] * r[j+1] / r_tmp;
314 
315  dcomplex c_E = (c_Rayleigh - c_Rayleigh_prev) / c_Rayleigh;
316 
317  c_Rayleigh_prev = c_Rayleigh;
318 
319  N_L_tmp = j + 1;
320 
321  // vout.paranoiac(m_vl, "N_L_tmp,abs(c_E),m_Tol_L = %d %f %f\n",N_L_tmp,abs(c_E),m_Tol_L);
322 
323  if (abs(c_E) < m_Tol_L) {
324  // vout.paranoiac(m_vl, "N_L_tmp = %d\n",N_L_tmp);
325 
326  // break;
327  is_converged_L = true;
328  }
329  }
330  }
331 
332 
333  std::vector<double> sigma(m_N_L + 1);
334  std::vector<dcomplex> gamma_prime(m_N_L + 1);
335 
336  // NB. tau(m_N_L,m_N_L+1), not (m_N_L+1,m_N_L+1)
337  std::vector<dcomplex> tau(m_N_L * (m_N_L + 1));
338  int ij, ji;
339 
340  for (int j = 1; j < N_L_tmp + 1; ++j) {
341  for (int i = 1; i < j; ++i) {
342  ij = index_ij(i, j);
343 
344  dcomplex r_ji = dotc(r[j], r[i]);
345  tau[ij] = conj(r_ji) / sigma[i]; // tau[ij] = (r[j] * r[i]) / sigma[i];
346  axpy(r[j], -tau[ij], r[i]); // r[j] -= tau[ij] * r[i];
347  }
348 
349  sigma[j] = r[j].norm2(); // sigma[j] = r[j] * r[j];
350 
351  dcomplex r_0j = dotc(r[0], r[j]);
352  gamma_prime[j] = conj(r_0j) / sigma[j]; // gamma_prime[j] = (r[0] * r[j]) / sigma[j];
353  }
354 
355 
356  std::vector<dcomplex> gamma(m_N_L + 1);
357  dcomplex c_tmp;
358 
359  gamma[N_L_tmp] = gamma_prime[N_L_tmp];
360 
361  for (int j = N_L_tmp - 1; j > 0; --j) {
362  c_tmp = cmplx(0.0, 0.0);
363 
364  for (int i = j + 1; i < N_L_tmp + 1; ++i) {
365  ji = index_ij(j, i);
366  c_tmp += tau[ji] * gamma[i];
367  }
368 
369  gamma[j] = gamma_prime[j] - c_tmp;
370  }
371 
372 
373  // NB. gamma_double_prime(m_N_L), not (m_N_L+1)
374  std::vector<dcomplex> gamma_double_prime(m_N_L);
375 
376  for (int j = 1; j < N_L_tmp; ++j) {
377  c_tmp = cmplx(0.0, 0.0);
378 
379  for (int i = j + 1; i < N_L_tmp; ++i) {
380  ji = index_ij(j, i);
381  c_tmp += tau[ji] * gamma[i + 1];
382  }
383 
384  gamma_double_prime[j] = gamma[j + 1] + c_tmp;
385  }
386 
387 
388  axpy(x, gamma[1], r[0]); // x += gamma[ 1] * r[ 0];
389  axpy(r[0], -gamma_prime[N_L_tmp], r[N_L_tmp]); // r[0] -= gamma_prime[N_L_tmp] * r[N_L_tmp];
390  axpy(u[0], -gamma[N_L_tmp], u[N_L_tmp]); // u[0] -= gamma[ N_L_tmp] * u[N_L_tmp];
391 
392  for (int j = 1; j < N_L_tmp; ++j) {
393  axpy(x, gamma_double_prime[j], r[j]); // x += gamma_double_prime[j] * r[j];
394  axpy(r[0], -gamma_prime[j], r[j]); // r[0] -= gamma_prime[ j] * r[j];
395  axpy(u[0], -gamma[j], u[j]); // u[0] -= gamma[ j] * u[j];
396  }
397 
398  rr = r[0].norm2(); // rr = r[0] * r[0];
399 
400 
401 #pragma omp barrier
402 #pragma omp master
403  {
404  rho_prev = rho_prev2;
405  alpha_prev = alpha_prev2;
406  N_L_prev = N_L_tmp;
407  rho_prev *= -gamma_prime[N_L_tmp];
408  }
409 #pragma omp barrier
410 }
411 
412 
413 //====================================================================
414 //============================================================END=====
void set_parameters_DS_L(const int N_L, const double Tol_L)
BridgeIO vout
Definition: bridgeIO.cpp:278
void detailed(const char *format,...)
Definition: bridgeIO.cpp:82
void Register_string(const string &, const string &)
Definition: parameters.cpp:351
void solve_init(const Field &, double &)
double norm2() const
Definition: field.cpp:441
BiCGStab(DS_L) algorithm.
void general(const char *format,...)
Definition: bridgeIO.cpp:65
void Register_int(const string &, const int)
Definition: parameters.cpp:330
Container of Field-type object.
Definition: field.h:39
int nvol() const
Definition: field.h:116
Class for parameters.
Definition: parameters.h:38
void copy(Field &y, const Field &x)
copy(y, x): y = x
Definition: field.cpp:381
void solve(Field &solution, const Field &source, int &Nconv, double &diff)
int square_non_zero(const double v)
Definition: checker.cpp:41
int nin() const
Definition: field.h:115
dcomplex dotc(const Field &y, const Field &x)
Definition: field.cpp:92
void reset(const int Nin, const int Nvol, const int Nex, const element_type cmpl=COMPLEX)
Definition: field.h:84
void aypx(const double a, Field &y, const Field &x)
aypx(y, a, x): y := a * y + x
Definition: field.cpp:461
int nex() const
Definition: field.h:117
void paranoiac(const char *format,...)
Definition: bridgeIO.cpp:99
void axpy(Field &y, const double a, const Field &x)
axpy(y, a, x): y := a * x + y
Definition: field.cpp:168
void crucial(const char *format,...)
Definition: bridgeIO.cpp:48
static const std::string class_name
Base class for linear solver class family.
Definition: solver.h:38
static bool Register(const std::string &realm, const creator_callback &cb)
virtual void mult(Field &, const Field &)=0
multiplies fermion operator to a given field (2nd argument)
int non_negative(const int v)
Definition: checker.cpp:21
void Register_double(const string &, const double)
Definition: parameters.cpp:323
void set_parameters(const Parameters &params)
Base class of fermion operator family.
Definition: fopr.h:49
int fetch_double(const string &key, double &val) const
Definition: parameters.cpp:124
string get_string(const string &key) const
Definition: parameters.cpp:87
int fetch_int(const string &key, int &val) const
Definition: parameters.cpp:141
Bridge::VerboseLevel m_vl
Definition: solver.h:62
static VerboseLevel set_verbose_level(const std::string &str)
Definition: bridgeIO.cpp:28
static void assert_single_thread(const std::string &classname)
assert currently running on single thread.
int size() const
Definition: field.h:121