Bridge++  Ver. 1.1.x
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
eigensolver_IRLanczos.cpp
Go to the documentation of this file.
1 
14 #include "eigensolver_IRLanczos.h"
15 
16 using std::valarray;
17 using std::string;
18 
19 #ifdef USE_PARAMETERS_FACTORY
20 #include "parameters_factory.h"
21 #endif
22 
23 //- parameter entries
24 namespace {
25  void append_entry(Parameters& param)
26  {
27  param.Register_string("eigensolver_mode", "NULL");
28  param.Register_int("number_of_wanted_eigenvectors", 0);
29  param.Register_int("number_of_working_eigenvectors", 0);
30  param.Register_int("maximum_number_of_iteration", 0);
31  param.Register_double("convergence_criterion_squared", 0.0);
32  param.Register_double("threshold_value", 0.0);
33 
34  param.Register_string("verbose_level", "NULL");
35  }
36 
37 
38 #ifdef USE_PARAMETERS_FACTORY
39  bool init_param = ParametersFactory::Register("Eigensolver.IRLanczos", append_entry);
40 #endif
41 }
42 //- end
43 
44 //- parameters class
46 //- end
47 
48 //====================================================================
50 {
51  const string str_vlevel = params.get_string("verbose_level");
52 
53  m_vl = vout.set_verbose_level(str_vlevel);
54 
55  //- fetch and check input parameters
56  string str_sortfield_type;
57  int Nk, Np;
58  int Niter_eigen;
59  double Enorm_eigen, Vthreshold;
60 
61  int err = 0;
62  err += params.fetch_string("eigensolver_mode", str_sortfield_type);
63  err += params.fetch_int("number_of_wanted_eigenvectors", Nk);
64  err += params.fetch_int("number_of_working_eigenvectors", Np);
65  err += params.fetch_int("maximum_number_of_iteration", Niter_eigen);
66  err += params.fetch_double("convergence_criterion_squared", Enorm_eigen);
67  err += params.fetch_double("threshold_value", Vthreshold);
68 
69  if (err) {
70  vout.crucial(m_vl, "Eigensolver_IRLanczos: fetch error, input parameter not found.\n");
71  abort();
72  }
73 
74 
75  set_parameters(Nk, Np, Niter_eigen, Enorm_eigen, Vthreshold);
76 }
77 
78 
79 //====================================================================
81  int Niter_eigen, double Enorm_eigen,
82  double Vthreshold)
83 {
84  //- print input parameters
85  vout.general(m_vl, "Parameters of Eigensolver_IRLanczos:\n");
86  vout.general(m_vl, " Nk = %d\n", Nk);
87  vout.general(m_vl, " Np = %d\n", Np);
88  vout.general(m_vl, " Niter_eigen = %d\n", Niter_eigen);
89  vout.general(m_vl, " Enorm_eigen = %16.8e\n", Enorm_eigen);
90  vout.general(m_vl, " Vthreshold = %16.8e\n", Vthreshold);
91 
92  //- range check
93  int err = 0;
96  err += ParameterCheck::non_negative(Niter_eigen);
97  err += ParameterCheck::square_non_zero(Enorm_eigen);
98  // NB. Vthreshold == 0 is allowed.
99 
100  if (err) {
101  vout.crucial(m_vl, "Eigensolver_IRLanczos: parameter range check failed.\n");
102  abort();
103  }
104 
105  //- store values
106  m_Nk = Nk;
107  m_Np = Np;
108  m_Niter_eigen = Niter_eigen;
109  m_Enorm_eigen = Enorm_eigen;
110  m_Vthreshold = Vthreshold;
111 }
112 
113 
114 //====================================================================
115 void Eigensolver_IRLanczos::solve(valarray<double>& TDa, valarray<Field>& vk,
116  int& Nsbt, int& Nconv, const Field& b)
117 {
118  int Nk = m_Nk;
119  int Np = m_Np;
120  int Niter_eigen = m_Niter_eigen;
121  double Enorm_eigen = m_Enorm_eigen;
122  double Vthreshold = m_Vthreshold;
123 
124 
125  Nconv = -1;
126  Nsbt = 0;
127 
128  int Nm = Nk + Np;
129 
130  if (Nk + Np > TDa.size()) {
131  vout.crucial(m_vl, "Eigensolver_IRLanczos: valarray TDa is too small.\n");
132  abort();
133  } else if (Nk + Np > vk.size()) {
134  vout.crucial(m_vl, "Eigensolver_IRLanczos: valarray vk is too small.\n");
135  abort();
136  }
137 
138  valarray<double> TDb(Nm);
139  valarray<double> TDa2(Nm);
140  valarray<double> TDb2(Nm);
141  valarray<double> Qt(Nm * Nm);
142  valarray<int> Iconv(Nm);
143 
144  int Nin = vk[0].nin();
145  int Nvol = vk[0].nvol();
146  int Nex = vk[0].nex();
147  valarray<Field> B(Nm);
148  for (int k = 0; k < Nm; ++k) {
149  B[k].reset(Nin, Nvol, Nex);
150  }
151 
152  Field f(vk[0]);
153  Field v(vk[0]);
154 
155  vout.general(m_vl, " Nk = %d Np = %d\n", Nk, Np);
156  vout.general(m_vl, " Nm = %d\n", Nm);
157  vout.general(m_vl, " size of TDa = %d\n", TDa.size());
158  vout.general(m_vl, " size of vk = %d\n", vk.size());
159 
160  int k1 = 1;
161  int k2 = Nk;
162  int kconv = 0;
163 
164  int Kdis = 0;
165  int Kthreshold = 0;
166  double beta_k;
167 
168  //- Set initial vector
169  vk[0] = 1.0;
170  double vnorm = vk[0] * vk[0];
171  vk[0] = 1.0 / sqrt(vnorm);
172  // (uniform vector)
173 
174  //- Initial Nk steps
175  for (int k = 0; k < k2; ++k) {
176  step(Nm, k, TDa, TDb, vk, f);
177  }
178 
179  //- Restarting loop begins
180  for (int iter = 0; iter < Niter_eigen; ++iter) {
181  vout.paranoiac(m_vl, "\n iter=%d\n", iter);
182 
183  int Nm2 = Nm - kconv;
184 
185  for (int k = k2; k < Nm; ++k) {
186  step(Nm, k, TDa, TDb, vk, f);
187  }
188 
189  f *= TDb[Nm - 1];
190 
191  //- getting eigenvalues
192  for (int k = 0; k < Nm2; ++k) {
193  TDa2[k] = TDa[k + k1 - 1];
194  TDb2[k] = TDb[k + k1 - 1];
195  }
196  setUnit_Qt(Nm, Qt);
197  tqri(TDa2, TDb2, Nm2, Nm, Qt);
198 
199  //- sorting
200  m_sort->sort(Nm, TDa2);
201 
202  //- Implicitly shifted QR transformations
203  setUnit_Qt(Nm, Qt);
204  for (int ip = k2; ip < Nm; ++ip) {
205  double Dsh = TDa2[ip - kconv];
206  int kmin = k1;
207  int kmax = Nm;
208  qrtrf(TDa, TDb, Nm, Nm, Qt, Dsh, kmin, kmax);
209  }
210 
211  for (int i = 0; i < (Nk + 1); ++i) {
212  B[i] = 0.0;
213  }
214 
215  for (int j = k1 - 1; j < k2 + 1; ++j) {
216  for (int k = 0; k < Nm; ++k) {
217  B[j] += Qt[k + Nm * j] * vk[k];
218  }
219  }
220 
221  for (int j = k1 - 1; j < k2 + 1; ++j) {
222  vk[j] = B[j];
223  }
224 
225  //- Compressed vector f and beta(k2)
226  f *= Qt[Nm - 1 + Nm * (k2 - 1)];
227  f += TDb[k2 - 1] * vk[k2];
228  beta_k = f * f;
229  beta_k = sqrt(beta_k);
230 
231  vout.paranoiac(m_vl, " beta(k) = %20.14f\n", beta_k);
232 
233 
234  double beta_r = 1.0 / beta_k;
235  vk[k2] = beta_r * f;
236  TDb[k2 - 1] = beta_k;
237 
238  //- Convergence test
239  TDa2 = TDa;
240  TDb2 = TDb;
241  setUnit_Qt(Nm, Qt);
242 
243  tqri(TDa2, TDb2, Nk, Nm, Qt);
244  for (int k = 0; k < Nk; ++k) {
245  B[k] = 0.0;
246  }
247 
248  for (int j = 0; j < Nk; ++j) {
249  for (int k = 0; k < Nk; ++k) {
250  B[j] += Qt[k + j * Nm] * vk[k];
251  }
252  }
253 
254  Kdis = 0;
255  Kthreshold = 0;
256 
257  for (int i = 0; i < Nk; ++i) {
258  v = m_fopr->mult(B[i]);
259  double vnum = B[i] * v;
260  double vden = B[i] * B[i];
261 
262  // vout.paranoiac(m_vl, " vden = %20.14e\n",vden);
263 
264  TDa2[i] = vnum / vden;
265  v -= TDa2[i] * B[i];
266  double vv = v * v;
267 
268  vout.paranoiac(m_vl, " %4d %18.14f %18.14e\n", i, TDa2[i], vv);
269 
270  if (vv < Enorm_eigen) {
271  Iconv[Kdis] = i;
272  ++Kdis;
273  // if(fabs(TDa2[i]) > Vthreshold){
274  if (m_sort->converged(TDa2[i], Vthreshold)) {
275  ++Kthreshold;
276  }
277  }
278  } // i-loop end
279 
280 
281  vout.paranoiac(m_vl, " #modes converged: %d\n", Kdis);
282 
283 
284  if (Kthreshold > 0) {
285  // (there is a converged eigenvalue larger than Vthreshold.)
286  Nconv = iter;
287 
288  //- Sorting
289  for (int i = 0; i < Kdis; ++i) {
290  TDa[i] = TDa2[Iconv[i]];
291  vk[i] = B[Iconv[i]];
292  }
293 
294  m_sort->sort(Kdis, TDa, vk);
295 
296  Nsbt = Kdis - Kthreshold;
297 
298  vout.general(m_vl, "\n Converged:\n");
299  vout.general(m_vl, " Nconv = %d\n", Nconv);
300  vout.general(m_vl, " beta(k) = %20.14e\n", beta_k);
301  vout.general(m_vl, " Kdis = %d\n", Kdis);
302  vout.general(m_vl, " Nsbt = %d\n", Nsbt);
303 
304  return;
305  }
306  } // end of iter loop
307 
308 
309  if (Nconv == -1) {
310  vout.crucial(m_vl, "Eigensolver_IRLanczos: NOT converged.\n");
311  abort();
312  }
313 }
314 
315 
316 //====================================================================
317 void Eigensolver_IRLanczos::step(int Nm, int k, valarray<double>& TDa,
318  valarray<double>& TDb, valarray<Field>& vk,
319  Field& w)
320 {
321  if (k >= Nm) {
322  vout.crucial(m_vl, "Eigensolver_IRLanczos: k is larger than Nm.\n");
323  abort();
324  } else if (k == 0) { // Initial step
325  w = m_fopr->mult(vk[k]);
326  double alph = vk[k] * w;
327 
328  w -= alph * vk[k];
329  double beta = w * w;
330  beta = sqrt(beta);
331  double beta_r = 1.0 / beta;
332  vk[k + 1] = beta_r * w;
333 
334  TDa[k] = alph;
335  TDb[k] = beta;
336  } else { // Iteration step
337  w = m_fopr->mult(vk[k]);
338  w -= TDb[k - 1] * vk[k - 1];
339  double alph = vk[k] * w;
340 
341  w -= alph * vk[k];
342  double beta = w * w;
343  beta = sqrt(beta);
344  double beta_r = 1.0 / beta;
345  w *= beta_r;
346 
347  TDa[k] = alph;
348  TDb[k] = beta;
349 
350  schmidt_orthogonalization(w, vk, k);
351 
352  if (k < Nm - 1) vk[k + 1] = w;
353  }
354 }
355 
356 
357 //====================================================================
359  valarray<Field>& vk, int k)
360 {
361  for (int j = 0; j < k; ++j) {
362  dcomplex prod = ddotc_complex(vk[j], w);
363  w.daxpy(-prod, vk[j]);
364  }
365 }
366 
367 
368 //====================================================================
369 void Eigensolver_IRLanczos::setUnit_Qt(int Nm, valarray<double>& Qt)
370 {
371  for (int i = 0; i < Qt.size(); ++i) {
372  Qt[i] = 0.0;
373  }
374 
375  for (int k = 0; k < Nm; ++k) {
376  Qt[k + k * Nm] = 1.0;
377  }
378 }
379 
380 
381 //====================================================================
382 void Eigensolver_IRLanczos::tqri(valarray<double>& TDa,
383  valarray<double>& TDb,
384  int Nk, int Nm, valarray<double>& Qt)
385 {
386  int Niter = 100 * Nm;
387  int kmin = 1;
388  int kmax = Nk;
389  // (these parameters should be tuned)
390 
391 
392  int Nconv = -1;
393 
394  for (int iter = 0; iter < Niter; ++iter) {
395  //- determination of 2x2 leading submatrix
396  double dsub = TDa[kmax - 1] - TDa[kmax - 2];
397  double dd = sqrt(dsub * dsub + 4.0 * TDb[kmax - 2] * TDb[kmax - 2]);
398  double Dsh = 0.5 * (TDa[kmax - 2] + TDa[kmax - 1]
399  + fabs(dd) * (dsub / fabs(dsub)));
400  // (Dsh: shift)
401 
402  //- transformation
403  qrtrf(TDa, TDb, Nk, Nm, Qt, Dsh, kmin, kmax);
404 
405  //- Convergence criterion (redef of kmin and kmax)
406  for (int j = kmax - 1; j >= kmin; --j) {
407  double dds = fabs(TDa[j - 1]) + fabs(TDa[j]);
408  if (fabs(TDb[j - 1]) + dds > dds) {
409  kmax = j + 1;
410 
411  for (int j = 0; j < kmax - 1; ++j) {
412  double dds = fabs(TDa[j]) + fabs(TDa[j + 1]);
413 
414  if (fabs(TDb[j]) + dds > dds) {
415  kmin = j + 1;
416 
417  break;
418  }
419  }
420 
421  break;
422  }
423 
424  if (j == kmin) {
425  Nconv = iter;
426  vout.paranoiac(m_vl, " converged at iter = %d\n", Nconv);
427 
428  return;
429  }
430  } // end of j loop
431  } // end of iter loop
432 
433  if (Nconv == -1) {
434  vout.crucial(m_vl, "Eigensolver_IRLanczos: QL method NOT converged, Niter = %d.\n", Niter);
435  abort();
436  }
437 }
438 
439 
440 //====================================================================
441 void Eigensolver_IRLanczos::qrtrf(valarray<double>& TDa,
442  valarray<double>& TDb,
443  int Nk, int Nm, valarray<double>& Qt,
444  double Dsh, int kmin, int kmax)
445 {
446  int k = kmin - 1;
447  double x;
448 
449  double Fden = 1.0 / sqrt((TDa[k] - Dsh) * (TDa[k] - Dsh)
450  + TDb[k] * TDb[k]);
451  double c = (TDa[k] - Dsh) * Fden;
452  double s = -TDb[k] * Fden;
453 
454  double tmpa1 = TDa[k];
455  double tmpa2 = TDa[k + 1];
456  double tmpb = TDb[k];
457 
458  TDa[k] = c * c * tmpa1 + s * s * tmpa2 - 2.0 * c * s * tmpb;
459  TDa[k + 1] = s * s * tmpa1 + c * c * tmpa2 + 2.0 * c * s * tmpb;
460  TDb[k] = c * s * (tmpa1 - tmpa2) + (c * c - s * s) * tmpb;
461  x = -s * TDb[k + 1];
462  TDb[k + 1] = c * TDb[k + 1];
463 
464  for (int i = 0; i < Nk; ++i) {
465  double Qtmp1 = Qt[i + Nm * k];
466  double Qtmp2 = Qt[i + Nm * (k + 1)];
467  Qt[i + Nm * k] = c * Qtmp1 - s * Qtmp2;
468  Qt[i + Nm * (k + 1)] = s * Qtmp1 + c * Qtmp2;
469  }
470 
471  //- Givens transformations
472  for (int k = kmin; k < kmax - 1; ++k) {
473  double Fden = 1.0 / sqrt(x * x + TDb[k - 1] * TDb[k - 1]);
474  double c = TDb[k - 1] * Fden;
475  double s = -x * Fden;
476 
477  double tmpa1 = TDa[k];
478  double tmpa2 = TDa[k + 1];
479  double tmpb = TDb[k];
480  TDa[k] = c * c * tmpa1 + s * s * tmpa2 - 2.0 * c * s * tmpb;
481  TDa[k + 1] = s * s * tmpa1 + c * c * tmpa2 + 2.0 * c * s * tmpb;
482  TDb[k] = c * s * (tmpa1 - tmpa2) + (c * c - s * s) * tmpb;
483  TDb[k - 1] = c * TDb[k - 1] - s * x;
484  if (k != kmax - 2) {
485  x = -s * TDb[k + 1];
486  TDb[k + 1] = c * TDb[k + 1];
487  }
488 
489  for (int i = 0; i < Nk; ++i) {
490  double Qtmp1 = Qt[i + Nm * k];
491  double Qtmp2 = Qt[i + Nm * (k + 1)];
492  Qt[i + Nm * k] = c * Qtmp1 - s * Qtmp2;
493  Qt[i + Nm * (k + 1)] = s * Qtmp1 + c * Qtmp2;
494  }
495  }
496 }
497 
498 
499 //====================================================================
500 //============================================================END=====