Bridge++  Ver. 1.1.x
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
solver_BiCGStab_IDS_L_Cmplx.cpp
Go to the documentation of this file.
1 
15 
16 using std::valarray;
17 
18 #ifdef USE_PARAMETERS_FACTORY
19 #include "parameters_factory.h"
20 #endif
21 
22 #ifdef USE_FACTORY
23 namespace {
24  Solver *create_object(Fopr *fopr)
25  {
26  return new Solver_BiCGStab_IDS_L_Cmplx(fopr);
27  }
28 
29 
30  bool init = Solver::Factory::Register("BiCGStab_IDS_L_Cmplx", create_object);
31 }
32 #endif
33 
34 //- parameter entries
35 namespace {
36  void append_entry(Parameters& param)
37  {
38  param.Register_int("maximum_number_of_iteration", 0);
39  param.Register_double("convergence_criterion_squared", 0.0);
40 
41  param.Register_int("number_of_orthonormal_vectors", 0);
42  param.Register_double("tolerance_for_DynamicSelection_of_L", 0);
43 
44  param.Register_string("verbose_level", "NULL");
45  }
46 
47 
48 #ifdef USE_PARAMETERS_FACTORY
49  bool init_param = ParametersFactory::Register("Solver.BiCGStab_IDS_L_Cmplx", append_entry);
50 #endif
51 }
52 //- end
53 
54 //- parameters class
56 //- end
57 
58 //====================================================================
60 {
61  const string str_vlevel = params.get_string("verbose_level");
62 
63  m_vl = vout.set_verbose_level(str_vlevel);
64 
65  //- fetch and check input parameters
66  int Niter;
67  double Stop_cond;
68  int N_L;
69  double Tol_L;
70 
71  int err = 0;
72  err += params.fetch_int("maximum_number_of_iteration", Niter);
73  err += params.fetch_double("convergence_criterion_squared", Stop_cond);
74  err += params.fetch_int("number_of_orthonormal_vectors", N_L);
75  err += params.fetch_double("tolerance_for_DynamicSelection_of_L", Tol_L);
76 
77  if (err) {
78  vout.crucial(m_vl, "Solver_BiCGStab_IDS_L_Cmplx: fetch error, input parameter not found.\n");
79  abort();
80  }
81 
82 
83  set_parameters(Niter, Stop_cond);
84  set_parameters_DS_L(N_L, Tol_L);
85 }
86 
87 
88 //====================================================================
89 void Solver_BiCGStab_IDS_L_Cmplx::set_parameters(const int Niter, const double Stop_cond)
90 {
91  //- print input parameters
92  vout.general(m_vl, "Parameters of Solver_BiCGStab_IDS_L_Cmplx:\n");
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, "Solver_BiCGStab_IDS_L_Cmplx: parameter range check failed.\n");
103  abort();
104  }
105 
106  //- store values
107  m_Niter = Niter;
108  m_Stop_cond = Stop_cond;
109 }
110 
111 
112 //====================================================================
113 void Solver_BiCGStab_IDS_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, "Solver_BiCGStab_IDS_L_Cmplx: parameter range check failed.\n");
126  abort();
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  vout.detailed(m_vl, " BiCGStab_IDS_L_Cmplx solver starts\n");
140 
141  reset_field(b);
142 
143  vout.paranoiac(m_vl, " norm of b = %16.8e\n", b.norm2());
144  vout.paranoiac(m_vl, " size of b = %d\n", b.size());
145 
146  double snorm = 1.0 / b.norm2();
147  double rr;
148 
149  // Nconv = -1;
150  Nconv = 0;
151  s = b;
152 
153  solve_init(b, rr);
154 
155  vout.detailed(m_vl, " iter: %8d %22.15e\n", 0, rr * snorm);
156 
157  for (int iter = 0; iter < m_Niter; iter++) {
158  solve_step(rr);
159 
160  Nconv += 2 * N_L_p;
161 
162  // vout.detailed(m_vl, "iter,N_L: %8d %8d\n" , Nconv, N_L_p);
163  vout.detailed(m_vl, " iter: %8d %22.15e\n", Nconv, rr * snorm);
164 
165  if (rr * snorm < m_Stop_cond) {
166  s = m_fopr->mult(x);
167  s -= b;
168  diff = s.norm();
169 
170  if (diff * diff * snorm < m_Stop_cond) {
171  // NB. Nconv is calculated above.
172  break;
173  }
174 
175  s = x;
176  solve_init(b, rr);
177  }
178  }
179 
180 
181  s = m_fopr->mult(x);
182  s -= b;
183  diff = s.norm();
184 
185  if (diff * diff * snorm > m_Stop_cond) {
186  vout.crucial(m_vl, "BiCGStab_IDS_L_Cmplx solver not converged.\n");
187  abort();
188  }
189 
190  xq = x;
191 }
192 
193 
194 //====================================================================
196 {
197  int Nin = b.nin();
198  int Nvol = b.nvol();
199  int Nex = b.nex();
200 
201  if ((s.nin() != Nin) || (s.nvol() != Nvol) || (s.nex() != Nex)) {
202  s.reset(Nin, Nvol, Nex);
203  x.reset(Nin, Nvol, Nex);
204 
205  r_init.reset(Nin, Nvol, Nex);
206 
207  v_tmp.reset(Nin, Nvol, Nex);
208 
209  vout.paranoiac(m_vl, " Solver_BiCGStab_IDS_L_Cmplx: field size reset.\n");
210  }
211 
212  u.resize(m_N_L + 1);
213  r.resize(m_N_L + 1);
214 
215  for (int i = 0; i < m_N_L + 1; ++i) {
216  u[i].reset(Nin, Nvol, Nex);
217  r[i].reset(Nin, Nvol, Nex);
218  }
219 }
220 
221 
222 //====================================================================
224 {
225  x = s;
226 
227  // r[0] = b - A x_0, x_0 = s //
228  v_tmp = m_fopr->mult(x);
229  r[0] = b;
230  r[0] -= v_tmp;
231 
232  r_init = r[0];
233 
234  rr = r[0] * r[0];
235 
236  // NB. alpha_p = 0.0 \neq 1.0 //
237  rho_p = cmplx(1.0, 0.0);
238  alpha_p = cmplx(0.0, 0.0);
239  omega_p = cmplx(1.0, 0.0);
240 
241  u[0] = 0.0;
242 
243  N_L_p = m_N_L;
244 }
245 
246 
247 //====================================================================
249 {
250  double const_r, const_i, r_tmp;
251 
252  int N_L_tmp = 0; // superficial initialization
253  dcomplex c_Rayleigh_p = cmplx(0.0, 0.0);
254 
255 
256  rho_p *= -omega_p;
257 
258  for (int j = 0; j < N_L_p; ++j) {
259  // dcomplex rho = r[j] * r_init;
260  innerprod_c(const_r, const_i, r[j], r_init);
261  dcomplex rho = cmplx(const_r, -const_i);
262 
263  dcomplex beta = alpha_p * (rho / rho_p);
264  rho_p = rho;
265 
266  for (int i = 0; i < j + 1; ++i) {
267  // u[i] = r[i] - beta * u[i];
268  mult_c(v_tmp, u[i], real(beta), imag(beta));
269  u[i] = r[i] - v_tmp;
270  }
271 
272  u[j + 1] = m_fopr->mult(u[j]);
273 
274  // dcomplex gamma = u[j+1] * r_init;
275  innerprod_c(const_r, const_i, u[j + 1], r_init);
276  dcomplex gamma = cmplx(const_r, -const_i);
277 
278  alpha_p = rho_p / gamma;
279 
280  for (int i = 0; i < j + 1; ++i) {
281  // r[i] -= alpha_p * u[i+1];
282  mult_c(v_tmp, u[i + 1], real(alpha_p), imag(alpha_p));
283  r[i] -= v_tmp;
284  }
285 
286  r[j + 1] = m_fopr->mult(r[j]);
287 
288  // x += alpha_p * u[0];
289  mult_c(v_tmp, u[0], real(alpha_p), imag(alpha_p));
290  x += v_tmp;
291 
292 
293  //- calculate the Rayleigh quotient for N_L_tmp
294 
295  // dcomplex c_Rayleigh = (r[j] * r[j+1]) / (r[j] * r[j]);
296  r_tmp = r[j] * r[j];
297 
298  innerprod_c(const_r, const_i, r[j], r[j + 1]);
299  dcomplex c_Rayleigh = cmplx(const_r, const_i) / r_tmp;
300 
301  dcomplex c_E = (c_Rayleigh - c_Rayleigh_p) / c_Rayleigh;
302 
303  c_Rayleigh_p = c_Rayleigh;
304  N_L_tmp = j + 1;
305 
306  // 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);
307 
308  if (abs(c_E) < m_Tol_L) {
309  // vout.paranoiac(m_vl, "N_L_tmp = %d\n",N_L_tmp);
310 
311  break;
312  }
313  }
314 
315 
316  N_L_p = N_L_tmp;
317 
318 
319  valarray<double> sigma(m_N_L + 1);
320  valarray<dcomplex> gamma_prime(m_N_L + 1);
321 
322  // NB. tau(m_N_L,m_N_L+1), not (m_N_L+1,m_N_L+1)
323  valarray<dcomplex> tau(m_N_L * (m_N_L + 1));
324  int ij, ji;
325 
326  for (int j = 1; j < N_L_tmp + 1; ++j) {
327  for (int i = 1; i < j; ++i) {
328  ij = index_ij(i, j);
329 
330  // tau[i,j] = (r[j] * r[i]) / sigma[i];
331  innerprod_c(const_r, const_i, r[j], r[i]);
332  tau[ij] = cmplx(const_r, -const_i) / sigma[i];
333 
334  // r[ j] -= tau[i,j] * r[i];
335  mult_c(v_tmp, r[i], real(tau[ij]), imag(tau[ij]));
336  r[j] -= v_tmp;
337  }
338 
339 
340  sigma[j] = r[j] * r[j];
341 
342 
343  // gamma_prime[j] = (r[0] * r[j]) / sigma[j];
344  innerprod_c(const_r, const_i, r[0], r[j]);
345  gamma_prime[j] = cmplx(const_r, -const_i) / sigma[j];
346  }
347 
348 
349  valarray<dcomplex> gamma(m_N_L + 1);
350  dcomplex c_tmp;
351 
352  gamma[N_L_tmp] = gamma_prime[N_L_tmp];
353  omega_p = gamma[N_L_tmp];
354 
355  for (int j = N_L_tmp - 1; j > 0; --j) {
356  c_tmp = cmplx(0.0, 0.0);
357 
358  for (int i = j + 1; i < N_L_tmp + 1; ++i) {
359  ji = index_ij(j, i);
360  c_tmp += tau[ji] * gamma[i];
361  }
362 
363  gamma[j] = gamma_prime[j] - c_tmp;
364  }
365 
366 
367  // NB. gamma_double_prime(m_N_L), not (m_N_L+1)
368  valarray<dcomplex> gamma_double_prime(m_N_L);
369 
370  for (int j = 1; j < N_L_tmp; ++j) {
371  c_tmp = cmplx(0.0, 0.0);
372 
373  for (int i = j + 1; i < N_L_tmp; ++i) {
374  ji = index_ij(j, i);
375  c_tmp += tau[ji] * gamma[i + 1];
376  }
377 
378  gamma_double_prime[j] = gamma[j + 1] + c_tmp;
379  }
380 
381  // x += gamma[ 1] * r[ 0];
382  // r[0] -= gamma_prime[N_L_tmp] * r[N_L_tmp];
383  // u[0] -= gamma[ N_L_tmp] * u[N_L_tmp];
384 
385  mult_c(v_tmp, r[0], real(gamma[1]), imag(gamma[1]));
386  x += v_tmp;
387 
388  mult_c(v_tmp, r[N_L_tmp], real(gamma_prime[N_L_tmp]), imag(gamma_prime[N_L_tmp]));
389  r[0] -= v_tmp;
390 
391  mult_c(v_tmp, u[N_L_tmp], real(gamma[N_L_tmp]), imag(gamma[N_L_tmp]));
392  u[0] -= v_tmp;
393 
394 
395  for (int j = 1; j < N_L_tmp; ++j) {
396  // x += gamma_double_prime[j] * r[j];
397  // r[0] -= gamma_prime[ j] * r[j];
398  // u[0] -= gamma[ j] * u[j];
399 
400  mult_c(v_tmp, r[j], real(gamma_double_prime[j]), imag(gamma_double_prime[j]));
401  x += v_tmp;
402 
403  mult_c(v_tmp, r[j], real(gamma_prime[j]), imag(gamma_prime[j]));
404  r[0] -= v_tmp;
405 
406  mult_c(v_tmp, u[j], real(gamma[j]), imag(gamma[j]));
407  u[0] -= v_tmp;
408  }
409 
410 
411  //- calculate the residual difference for N_L_p
412  double rr_p = rr;
413 
414  rr = r[0] * r[0];
415 
416  double c_phi = abs(rr - rr_p) / rr_p;
417 
418  // NB. other criterion for c_phi is possible, m_Tol_phi /= m_Tol_L
419  if (c_phi < m_Tol_L) {
420  N_L_p = m_N_L;
421  }
422 }
423 
424 
425 //====================================================================
426 void Solver_BiCGStab_IDS_L_Cmplx::innerprod_c(double& prod_r, double& prod_i,
427  const Field& v, const Field& w)
428 {
429  // prod = (v,w);
430 
431  int size = w.size();
432 
433  assert(v.size() == size);
434 
435  prod_r = 0.0;
436  prod_i = 0.0;
437 
438  for (int i = 0; i < size; i += 2) {
439  prod_r += v.cmp(i) * w.cmp(i) + v.cmp(i + 1) * w.cmp(i + 1);
440  prod_i += v.cmp(i) * w.cmp(i + 1) - v.cmp(i + 1) * w.cmp(i);
441  }
442 
443  prod_r = Communicator::reduce_sum(prod_r);
444  prod_i = Communicator::reduce_sum(prod_i);
445 }
446 
447 
448 //====================================================================
450  const Field& w,
451  const double& prod_r, const double& prod_i)
452 {
453  // v = dcomplex(prod_r,prod_i) * w;
454 
455  int size = w.size();
456 
457  assert(v.size() == size);
458 
459  double vr, vi;
460  for (int i = 0; i < size; i += 2) {
461  vr = prod_r * w.cmp(i) - prod_i * w.cmp(i + 1);
462  vi = prod_r * w.cmp(i + 1) + prod_i * w.cmp(i);
463 
464  v.set(i, vr);
465  v.set(i + 1, vi);
466  }
467 }
468 
469 
470 //====================================================================
471 //============================================================END=====