CHROMA
lovlapms_w.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Overlap-pole operator
3  */
4 #include "chromabase.h"
6 #include "meas/eig/gramschm.h"
7 
8 
9 #undef LOVLAPMS_RSD_CHK
10 
11 namespace Chroma
12 {
13 void lovlapms::operator() (LatticeFermion& chi, const LatticeFermion& psi,
14  enum PlusMinus isign) const
15 {
17 }
18 
19 //! Apply the GW operator onto a source std::vector
20 /*! \ingroup linop
21  *
22  * This routine applies the 4D GW operator onto a source
23  * std::vector. The coeffiecients for the approximation get
24  * wired into the class by the constructor and should
25  * come fromt fermion action.
26  *
27  * The operator applied is:
28  * D = (1/2)[ (1+m) + (1-m)gamma_5 sgn(H_w) ] psi
29  * or D^{dag} = (1/2)[ (1+m) + (1-m) sgn(H_w) gamma_5 psi
30  *
31  *
32  * \param chi result std::vector (Write)
33  * \param psi source std::vector (Read)
34  * \param isign Hermitian Conjugation Flag
35  * ( PLUS = no dagger| MINUS = dagger ) (Read)
36  */
37 void lovlapms::operator() (LatticeFermion& chi, const LatticeFermion& psi,
38  enum PlusMinus isign, Real epsilon) const
39 {
40  START_CODE();
41 
42  LatticeFermion tmp1, tmp2;
43 
44  // Gamma_5
45  int G5 = Ns*Ns - 1;
46 
47  // Mass for shifted system
48  Real mass = Real(1 + m_q) / Real(1 - m_q);
49 
50 
51  switch (isign)
52  {
53  case PLUS:
54  // Non-Dagger: psi is source and tmp1
55  // chi := gamma_5 * (gamma_5 * mass + sgn(H)) * Psi
56  tmp1 = psi;
57  break;
58 
59  case MINUS:
60  // Dagger: apply gamma_5 to source psi to make tmp1
61  // chi := (mass + sgn(H) * gamma_5) * Psi
62  tmp1 = Gamma(G5) * psi;
63  break;
64 
65  default:
66  QDP_error_exit("unknown isign value", isign);
67  }
68 
69 
70  chi = zero;
71 
72  // Project out eigenvectors of source if desired
73  // chi += func(lambda) * EigVec * <EigVec, psi>
74  // Usually "func(.)" is sgn(.); it is precomputed in EigValFunc.
75  // for all the eigenvalues
76  //
77  // Also we must bear in mind that if we want the dagger of the
78  // operator we must use gamma_5 psi instead of psi
79  //
80  // at this stage tmp1 holds either psi or gamma_5 psi as required
81  // so we must project from tmp1
82 
83  if (NEig > 0)
84  {
85  Complex cconsts;
86  LatticeFermion tmp3 = tmp1;
87 
88  for(int i = 0; i < NEig; ++i)
89  {
90 
91  // BUG Should this not be innerProduct(EigVec[i], psi) ???
92  // or innerProduct(EigVec[i], g5 psi) ????
93 
94  cconsts = innerProduct(EigVec[i], tmp3);
95  tmp1 -= EigVec[i] * cconsts;
96 
97  cconsts *= EigValFunc[i];
98  chi += EigVec[i] * cconsts;
99  }
100 
101  // tmp3 should go out of scope here and be freed.
102  }
103 
104  // tmp1 <- H * Projected tmp_1, where tmp1 = psi or gamma_5 psi as needed
105  // <- gamma_5 * M * tmp1
106  (*M)(tmp2, tmp1, PLUS);
107  tmp1 = Gamma(G5) * tmp2;
108 
109 
110 
111  Double c = norm2(tmp1);
112 
113  /* If exactly 0 norm, then solution must be 0 (for pos. def. operator) */
114  if (toBool(c == 0))
115  {
116  chi = zero;
117  END_CODE();
118  return;
119  }
120 
121 
122 
123  // *******************************************************************
124  // Solve (MdagM + rootQ_n) chi_n = tmp1 where
125  //
126  // tmp1 = H psi or H_gamma_5 psi
127  //
128 #ifdef LOVLAPMS_RSD_CHK
129  LatticeFermion b_vec = tmp1;
130  LatticeFermion x;
131 #endif
132  LatticeFermion Ap;
133  LatticeFermion r;
134  multi1d<LatticeFermion> p(numroot);
135 
136  Real a; // Alpha for unshifted (isz) system
137  Real as; // alpha for current shifted system
138  Real b; // Beta for unshifted system
139  Real bp; // Beta previous for unshifted system
140 
141  Double ztmp; // Assorted reals (shifted residues)
142  Double cp;
143  Double d;
144  Real z0; // temporary value for zeta previous
145  Real z1; // temporary value for zeta current
146 
147  multi1d<Real> bs(numroot); // beta for shifted system
148  multi2d<Real> z(2,numroot); // zeta for shifted system
149 
150  Double chi_sq_new; // sgn() convergence criterion
151  Double chi_sq_diff;
152  multi1d<bool> convsP(numroot); // convergence mask for shifted system
153  bool convP; // overall convergence mask
154 
155  int iz; // Temporary index for getting at
156  // zeta values in z array
157 
158  int s; // Counter for loops over shifts
159 
160  // We are solving with 2/(1-mu) D(mu) here so
161  // I should readjust the residuum by (1-mu)/2
162  Real epsilon_normalise = epsilon*(Real(1)-m_q)/Real(2);
163 
164  // Real target for sign function -- from Wuppertal paper
165  Real epsilon_target = epsilon_normalise/(Real(2) + epsilon_normalise);
166 
167  // Square it up
168  Real rsdcg_sq = epsilon_target*epsilon_target; // Target residuum squared
169 
170  // Get relative target
171  Real rsd_sq = norm2(psi)*rsdcg_sq; // Used for relative residue comparisons
172  // r_t^2 * || r ||^2
173 
174 
175  // By default, rootQ(isz) is considered the smallest shift
176  int isz = numroot-1; // isz identifies system with smalles shift
177 
178 
179  // chi[0] := mass*psi + c0*H*tmp1 + Eigvecs;
180  if (isign == PLUS)
181  {
182  // chi := gamma_5 * (gamma_5 * mass + eps(H)) * Psi
183  // Final mult by gamma_5 is at end
184  tmp2 = Gamma(G5) * psi;
185 
186  // This will be an axpy
187  chi += tmp2 * mass;
188  }
189  else
190  {
191  // chi := (mass + eps(H) * gamma_5) . Psi
192  chi += psi * mass;
193  }
194 
195  // Multiply in P(0) -- this may well be 0 for type 0 rational approximations
196  chi += tmp1 * constP;
197 
198 
199  // r[0] := p[0] := tmp1
200  r = tmp1;
201 
202  // Initialise search vectors for shifted systems
203  for(s = 0; s < numroot; ++s){
204  p[s] = tmp1;
205  }
206 
207  // Set convergence masks to false
208  convsP = false;
209  convP = false;
210 
211 
212  iz = 1; // z_index z[ iz , s ] holds zeta(s)
213  // z[ 1-iz, s ] holds zeta_minus(s)
214 
215  z = 1; // This fills both zeta and zeta_minus
216 
217  a = 0; // Alpha for unshifted
218  b = 1; // beta for unshifted
219 
220  int k;
221  // Do the iterations proper
222  for(k = 0; k <= MaxCG && ! convP ; ++k) {
223 
224  // Unshifted beta value: b[k] -- k is iteration index
225  // b[k] := | r[k] |**2 / < p[k], Ap[k] > ;
226  // First compute d = < p, A.p >
227  // Ap = A . p
228 
229  // This bit computes
230  // Ap = [ M^dag M + rootQ(isz) ] p_isz
231 
232 
233  (*MdagM)(Ap, p[isz], PLUS);
234  Ap += p[isz] * rootQ[isz];
235 
236  // Project out eigenvectors
237  if (k % ReorthFreq == 0) {
238  GramSchm(Ap, EigVec, NEig, all);
239  }
240 
241  // d = < p, A.p >
242  d = innerProductReal(p[isz], Ap); // 2 Nc Ns flops
243 
244  bp = b; // Store previous unshifted beta
245  b = -Real(c/d); // New unshifted beta
246 
247  // Compute the shifted bs and z
248  bs[isz] = b;
249 
250 
251  // iz now points to previous z's
252  iz = 1 - iz;
253 
254  // Compute new shifted beta and zeta values
255  // as per Beat Jegerlehner's paper: hep-lat/9612014
256  // eqns 2.42, 2.44 on page 7
257  for(s = 0; s < numroot; s++)
258  {
259 
260  // Do this to avoid mitsmp compiler bug !!
261  z0 = z[1-iz][s]; // The current z for the system under considerstion
262  z1 = z[iz][s] ; // The previous z for the system under consideration
263 
264  // We only compute beta and z factors if
265  // i) The system is not yet converged
266  // ii) The system is shifted
267  if (s != isz && !convsP[s]) {
268 
269  // We write the new z-s in the place of the previous ones.
270  // Our ones will become previous next time around
271  z[iz][s] = z0*z1*bp ;
272  z[iz][s] /= b*a*(z1 - z0) + z1*bp*(1 - (rootQ[s] - rootQ[isz])*b);
273  bs[s] = b * z[iz][s] / z0;
274 
275  }
276  }
277 
278 
279  // New residual of system with smallest shift
280  // r[k+1] += b[k] A . p[k] ;
281  r += b * Ap; // 2 Nc Ns flops
282 
283 #ifdef LOVLAPMS_RSD_CHK
284  x -= b * p[isz];
285 #endif
286 
287  // Project out eigenvectors
288  if (k % ReorthFreq == 0) {
289  GramSchm (r, EigVec, NEig, all);
290  }
291 
292  // Work out new iterate for sgn(H).
293  //
294  // This in effect updates all x vectors and performs
295  // immediately the linear sum.
296  // However, the x's are never explicitly computed. Rather
297  // the changes they would get get rolled onto the chi immediately
298  //
299  // chi[k+1] -= sum_{shifts} resP_{shift} b_{shift}[k] p_{shift}[k] ;
300  //
301  // since we are doing the linear combinations we multiply in the
302  // constant in the numerator too.
303 
304  // smallest shift first
305  Real(rtmp);
306  rtmp = resP[isz] * b;
307  tmp1 = p[isz] * rtmp; // 2 Nc Ns flops
308 
309  // Now the other shifts.
310  // Converged systems haven' changed, so we only add results
311  // from the unconverged systems
312  for(s = 0; s < numroot; ++s) {
313  if(s != isz && !convsP[s]) {
314 
315  rtmp = bs[s] * resP[s];
316  tmp1 += p[s] * rtmp; // 2 Nc Ns flops
317  }
318  }
319 
320  // Now update the sgn(H) with the above accumulated linear sum
321  chi -= tmp1; // 2 Nc Ns flops
322 
323  // Store in cp the previous value of c
324  // cp = | r[k] |**2
325  cp = c;
326 
327  // And compute the current norm of r into the (now saved) c
328  // c = | r[k] |**2
329  c = norm2(r); // 2 Nc Ns flops
330 
331  // Work out the alpha factor for the system with smallest shift.
332  // a[k+1] := |r[k]|**2 / |r[k-1]|**2 ;
333  a = Real(c/cp);
334 
335  // Now update search vectors p_{shift}[k]
336  // the system with smallest shift gets updated as
337  //
338  // p[k+1] := r[k+1] + a[k+1] p[k];
339 
340  // The updated systems get updated as
341  //
342  // ps[k+1] := zs[k+1] r[k+1] + as[k+1] ps[k];
343  //
344  // where the as[]-s are the shifted versions of alpha.
345  // we must first computed these as per Beat's paper hep-lat/9612014
346  // eq 2.43 on page 7.
347  //
348  // As usual we only update the unconverged systems
349  for(s = 0; s < numroot; ++s)
350  {
351 
352  if (s == isz) {
353  // Smallest shift
354  // p[k+1] = r[k+1] + a[k+1] p[k]
355  //
356  // k is iteration index
357  p[s] *= a; // Nc Ns flops
358  p[s] += r; // Nc Ns flops
359 
360  }
361  else {
362  if (! convsP[s]) {
363  // Unshifted systems
364  // First compute shifted alpha
365  as = a * z[iz][s]*bs[s] / (z[1-iz][s]*b);
366 
367  // Then update
368  // ps[k+1] := zs[k+1] r[k+1] + as[k+1] ps[k];
369  //
370  // k is iteration index
371  p[s] *= as; // Nc Ns flops
372  p[s] += r * z[iz][s]; // Nc Ns flops
373 
374  }
375  }
376  }
377 
378 #if 0
379  // Project out eigenvectors
380  if (k % ReorthFreq == 0)
381  GramSchm (p, numroot, EigVec, NEig, all);
382 #endif
383 
384  // Convergence tests start here.
385  //
386  // These are two steps:
387  //
388  // i) Check that the shifted vectors have converged
389  // by checking their accumulated residues
390  //
391  // ii) Check that the sign function itself has converged
392  //
393  //
394  // We set the global convergence flag to true, and then if
395  // any vectors are unconverged this will flip the global flag back
396  // to false
397  convP = true; // Assume convergence and prove
398  // otherwise
399 
400  for(s = 0; s < numroot; ++s) {
401 
402  // Only deal with unconverged systems
403  if (! convsP[s]) {
404 
405  // Compute the shifted residuum squared
406  //
407  // r_{shift} = || r || * zeta(shift)
408  //
409  // hence || r_shift ||^2 = || r ||^2 * zeta_shift^2
410  //
411  // || r^2 || is already computed in c
412  //
413  // Store || r_shift ||^2 in ztmp
414  ztmp = Real(c) * z[iz][s]*z[iz][s];
415 
416  // Check ztmp is smaller than the target residuum
417  bool btmp = toBool(ztmp < rsd_sq);
418  convP = convP & btmp;
419  convsP[s] = btmp;
420  }
421  }
422 
423 
424 #ifdef LOVLAPMS_RSD_CHK
425  if(convP) {
426  LatticeFermion tmp_normcheck;
427  (*MdagM)(tmp_normcheck, x, PLUS);
428  tmp_normcheck += rootQ[isz]*x;
429  tmp_normcheck -= b_vec;
430  Double norm2check = norm2(tmp_normcheck);
431  Double check_ztmp = Real(c) * z[iz][isz]*z[iz][isz];
432  QDPIO::cout << "|| b - (Q_isz + MM)x || = " << norm2check << " accum = " << check_ztmp << std::endl;
433  }
434 #endif
435 
436  // Now check convergence of the sgn() itself.
437  // It was updated with
438  // sum resP(shift) beta(shift) p_shift
439  // and this quantity is still in tmp1.
440  //
441  // So norm tmp1 is like an abolute error in sgn() aka: Delta sgn()
442  //
443  // Here we ensure Delta sgn() < target r^2 || sgn H[k-1] ||
444  //
445  // ie that the relative error in sgn() is smaller than the target.
446  // sgn H is kept in chi
447  //
448  // Only converge if chi is converged. If vectors converge first, then error
449 
450 #if 0
451  if (k > 0 && !convP) {
452 
453  // Get target r^2 * || sgn (H) ||^2
454  chi_sq_new = rsd_sq * norm2(chi);
455 
456  // Get || Delta sgn()
457  chi_sq_diff = norm2(tmp1); // the diff of old and new soln
458 
459 #if 0
460  QDPIO::cout << "Iter " << k << " || delta Sgn() || " << sqrt(chi_sq_diff) << std::endl;
461 #endif
462  // Check convergence
463  bool btmp = toBool(chi_sq_diff < chi_sq_new);
464 
465  // If we havent converged globally but the vectors have then error
466  if (! btmp && convP) {
467  QDP_error_exit("vectors converged but not final chi");
468  }
469 
470  // cnvP = convP & btmp;
471  convP = btmp;
472  }
473 
474 #endif
475  }
476 
477  QDPIO::cout << "Overlap Inner Solve (lovlapms): " << k << " iterations " << std::endl;
478  // End of MULTI SHIFTERY
479 
480  // Now fix up the thing. Multiply in gamma5 if needed
481  // and then rescale to correct normalisation.
482 
483  if (isign == PLUS)
484  {
485  // chi := gamma_5 * (gamma_5 * mass + eps(H)) * Psi
486  tmp1 = Gamma(G5) * chi;
487  chi = tmp1;
488  }
489 
490  // Rescale to the correct normalization
491  chi *= 0.5 * (1 - m_q);
492 
493  END_CODE();
494 }
495 
496 } // End Namespace Chroma
497 
Primary include file for CHROMA library code.
const Real m_q
Definition: lovlapms_w.h:100
const multi1d< LatticeFermion > EigVec
Definition: lovlapms_w.h:105
const Real constP
Definition: lovlapms_w.h:102
const multi1d< Real > EigValFunc
Definition: lovlapms_w.h:106
const multi1d< Real > resP
Definition: lovlapms_w.h:103
const int ReorthFreq
Definition: lovlapms_w.h:110
const Real RsdCG
Definition: lovlapms_w.h:109
void operator()(LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign) const
Apply the operator onto a source std::vector.
Definition: lovlapms_w.cc:13
const multi1d< Real > rootQ
Definition: lovlapms_w.h:104
Gramm-Schmidt orthogonolization.
void GramSchm(multi1d< LatticeFermion > &psi, const int Npsi, const multi1d< LatticeFermion > &vec, const int Nvec, const Subset &sub)
Gramm-Schmidt orthogonolization.
Definition: gramschm.cc:127
Internal Overlap-pole operator.
int z
Definition: meslate.cc:36
int x
Definition: meslate.cc:34
int iz
Definition: meslate.cc:32
Real rtmp
Definition: meslate.cc:59
Double tmp2
Definition: mesq.cc:30
Double tmp3
Definition: mesq.cc:31
int epsilon(int i, int j, int k)
BinaryReturn< C1, C2, FnInnerProduct >::Type_t innerProduct(const QDPSubType< T1, C1 > &s1, const QDPType< T2, C2 > &s2)
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
QDP_error_exit("too many BiCG iterations", n_count, rsd_sq, cp, c, re_rvr, im_rvr, re_a, im_a, re_b, im_b)
int G5
Definition: pbg5p_w.cc:57
Double c
Definition: invbicg.cc:108
Real rsd_sq
Definition: invbicg.cc:121
int i
Definition: pbg5p_w.cc:55
Double mass
Definition: pbg5p_w.cc:54
@ MINUS
Definition: chromabase.h:45
@ PLUS
Definition: chromabase.h:45
Double cp
Definition: invbicg.cc:107
multi1d< LatticeFermion > chi(Ncb)
Complex a
Definition: invbicg.cc:95
LatticeFermion psi
Definition: mespbg5p_w.cc:35
DComplex d
Definition: invbicg.cc:99
START_CODE()
Complex b
Definition: invbicg.cc:96
Double zero
Definition: invbicg.cc:106
int k
Definition: invbicg.cc:119
multi1d< LatticeFermion > s(Ncb)
FloatingPoint< double > Double
Definition: gtest.h:7351
int isz
Definition: pade_trln_w.cc:151