CHROMA
eoprec_ht_contfrac5d_linop_array_w.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief 4D-style even-odd preconditioned domain-wall linear operator
3  */
4 
5 #include "chromabase.h"
8 
9 using namespace QDP::Hints;
10 
11 namespace Chroma
12 {
13  // Full constructor
14  EvenOddPrecHtContFrac5DLinOpArray::EvenOddPrecHtContFrac5DLinOpArray(
16  const Real& _m_q,
17  const Real& _OverMass,
18  int _N5,
19  const Real& _scale_fac,
20  const multi1d<Real>& _alpha,
21  const multi1d<Real>& _beta,
22  const Real& b5_,
23  const Real& c5_,
24  const bool _isLastZeroP ) :
25  m_q(_m_q), OverMass(_OverMass), N5(_N5), scale_fac(_scale_fac),
26  alpha(_alpha), beta(_beta), isLastZeroP(_isLastZeroP), b5(b5_), c5(c5_)
27  {
28  START_CODE();
29 
30  Dslash.create(fs, _N5);
31 
32  // The mass ratio
33  Real mass = ( Real(1) + m_q ) / (Real(1) - m_q);
34 
35  // f_+ = (b5 + c5)
36  f_plus = b5_ + c5_;
37 
38  // f_- = (b5 - c5)
39  f_minus = b5_ - c5_;
40 
41  // Now compute some coefficients.
42  // First the beta_tilde_i
43  // Basically this is beta[n]*Hsign*scale_fac
44  // Now N5 is always odd. So the first Hsign is +
45  // and the last one should also be
46  // Hence at the end of this loop Hsign should be flipped from +->-
47  beta_tilde.resize(N5);
48  int Hsign = 1;
49  for(int i=0; i < N5; i++) {
50 
51  beta_tilde[i] = beta[i]*Hsign*scale_fac*f_plus;
52 
53  // Flip Hsign
54  Hsign = -Hsign;
55 
56 
57  }
58 
59  // Sanity Check
60  if ( Hsign > 0 ) {
61  QDPIO::cerr << "Something is wrong. At the end of this loop"
62  << " Hsign should be -ve" << std::endl;
63  }
64 
65  alpha_tilde.resize(N5-1);
66  for(int i=0; i < N5-1; i++) {
67 
68  alpha_tilde[i] = alpha[i]*(Real(2) + f_minus*(Nd - OverMass));
69 
70  }
71 
72 
73  // Now the a_i's and b_i's
74  a.resize(N5);
75  for(int i=0; i < N5-1; i++) {
76  a[i] = beta_tilde[i]*(Nd - OverMass);
77  }
78  a[N5-1] = mass*(Real(2) + f_minus*(Nd - OverMass))
79  + (beta_tilde[N5-1]*(Nd - OverMass));
80 
81  /*
82  QDPIO::cout << "Nd - OverMass = " << Nd - OverMass << std::endl;
83  for(int i=0; i < N5; i++) {
84  QDPIO::cout << "a["<<i<<"]= " << a[i] << std::endl;
85  }
86  */
87  // Now the d-s
88  d.resize(N5);
89  invd.resize(N5);
90 
91  d[0] = a[0];
92  invd[0] = Real(1)/d[0];
93  for(int i=1; i < N5; i++) {
94  d[i] = a[i] - (alpha_tilde[i-1]*alpha_tilde[i-1])/d[i-1];
95  invd[i] = Real(1)/d[i];
96  }
97 
98  /*
99  for(int i=0; i < N5; i++) {
100  QDPIO::cout << "d["<<i<<"]=" << d[i] << std::endl;
101  }
102  */
103 
104  // Now the u-s
105  u.resize(N5-1);
106  for(int i=0; i < N5-1; i++) {
107  u[i] = alpha_tilde[i]/d[i];
108  }
109 
110  /*
111  for(int i=0; i < N5-1; i++) {
112  QDPIO::cout << "u["<<i<<"] = " << u[i] << std::endl;
113  }
114  */
115  END_CODE();
116  }
117 
118 
119 
120 
121  //! Apply the even-even (odd-odd) coupling piece of the domain-wall fermion operator
122  /*!
123  * \ingroup linop
124  *
125  * The operator acts on the entire lattice
126  *
127  * \param psi Pseudofermion field (Read)
128  * \param isign Flag ( PLUS | MINUS ) (Read)
129  * \param cb checkerboard ( 0 | 1 ) (Read)
130  *
131  * 6*Nc*Ns + (N5-2)*10*Nc*Ns + 6Nc*Ns = 12*NcNs + 10*N5NcNs - 20*NcNs
132  * = (10N5 - 8)NcNs
133  */
134  void
136  const multi1d<LatticeFermion>& psi,
137  enum PlusMinus isign,
138  const int cb) const
139  {
140  START_CODE();
141 
142  if( chi.size() != N5 ) chi.resize(N5);
143 
144  // We don't care about the isign because our operator is Hermitian
145  // Apply matrix
146  // [ A_0 B_0 0 ... ] [ psi_0 ]
147  // [ B_0 A_1 B_1 ... ... ] [ psi_1 ]
148  // [ 0 ... ... ... ... ] [ psi_2 ]
149  // [ ... ... 0 B_N5-3 A_N5-2 B_N5-2 ] [ psi_N5-2 ]
150  // [ ... ... ... 0 B_N5-2 A_N5-1 ] [ psi_N5-1 ]
151 
152  // With A_i = gamma_5 a_i = a_i gamma_5
153  // and B_i = b_i I = alpha_tilde_i I
154 
155  // LatticeFermion tmp;
156  int G5=Ns*Ns-1;
157 
158  // First 0ne
159  //tmp[rb[cb]] = Gamma(G5)*psi[0];
160 
161  // 2*Nc*Ns flops/cbsite
162  chi[0][rb[cb]] = a[0]*(GammaConst<Ns,Ns*Ns-1>()*psi[0]);
163  if( N5 > 1 ) {
164 
165  // 4*Nc*Ns flops/cbsite
166  chi[0][rb[cb]] += alpha_tilde[0]*psi[1];
167  }
168 
169  // All the rest
170  for(int i=1; i < N5; i++) {
171 
172  // B_{i-1} psi_[i-1]
173  // chi[i][rb[cb]] = alpha_tilde[i-1]*psi[i-1];
174 
175  // A_{i} psi[i] = a_{i} g_5 psi[i]
176  // tmp[rb[cb]] = Gamma(G5)*psi[i];
177  // 6 NcNs flops/cbsite
178  chi[i][rb[cb]] = alpha_tilde[i-1]*psi[i-1] + a[i]*(GammaConst<Ns,Ns*Ns-1>()*psi[i]);
179 
180  // When i hits N5-1, we don't have the B_N5-1 term
181  if(i < N5-1) {
182  // 4NcNs flops/cbsite
183  chi[i][rb[cb]] += alpha_tilde[i]*psi[i+1];
184  }
185  }
186 
187  END_CODE();
188  }
189 
190 
191  //! Apply the inverse even-even (odd-odd)
192  /*!
193  * \ingroup linop
194  *
195  * Here we apply the LDU decomposition
196  *
197  * \param psi Pseudofermion field (Read)
198  * \param isign Flag ( PLUS | MINUS ) (Read)
199  * \param cb checkerboard ( 0 | 1 ) (Read)
200  *
201  * (N5-2)*6NcNs + 2NcNs + (N5-1)*4NcNs
202  * = 6N5 NcNs - 12 NcNs + 2NcNs + 4 N5 NcNs - 4NcNs
203  * = 10*N5*Nc*Ns -14NcNs
204  */
205  void
207  multi1d<LatticeFermion>& chi,
208  const multi1d<LatticeFermion>& psi,
209  enum PlusMinus isign,
210  const int cb) const
211  {
212  START_CODE();
213 
214  if( chi.size() != N5 ) chi.resize(N5);
215 
216  multi1d<LatticeFermion> y(N5);
217  moveToFastMemoryHint(y);
218 
219  // LatticeFermion tmp;
220  // Real coeff;
221 
222  const int G5 = Ns*Ns-1;
223 
224  // Solve L y = psi
225  // y=D^{-1}y
226  // together in one loop
227  y[0][rb[cb]] = psi[0];
228 
229  /* (N5 - 2)* 6NcNs */
230  for(int i = 1; i < N5; i++) {
231  y[i][rb[cb]] = psi[i] - u[i-1]*(GammaConst<Ns,Ns*Ns-1>()*y[i-1]);
232  y[i-1][rb[cb]] = invd[i-1]*(GammaConst<Ns,Ns*Ns-1>()*y[i-1]);
233  }
234  /* 2NcNs */
235  y[N5-1][rb[cb]] = invd[N5-1]*(GammaConst<Ns,Ns*Ns-1>()*y[N5-1]);
236 
237  // Backsubstitute U chi = y
238  chi[N5-1][rb[cb]] = y[N5-1];
239 
240  // (N5-1)*4NcNs
241  for(int i = N5-2; i >= 0; i--) {
242  // tmp = Gamma(G5)*chi[i+1];
243  chi[i][rb[cb]] = y[i] - u[i]*(GammaConst<Ns,Ns*Ns-1>()*chi[i+1]);
244  }
245 
246  //Done! That was not that bad after all....
247  //See, I told you so...
248  END_CODE();
249  }
250 
251  //! Apply the off diagonal block
252  /*!
253  * \param chi result (Modify)
254  * \param psi source (Read)
255  * \param isign Flag ( PLUS | MINUS ) (Read)
256  * \param cb checkerboard ( 0 | 1 ) (Read)
257  *
258  * 10*(N5-2)*NcNs+12*NcNs+ N5*1320
259  * (10N5 - 8)*NcNs + N5*1320
260  */
262  multi1d<LatticeFermion>& chi,
263  const multi1d<LatticeFermion>& psi,
264  enum PlusMinus isign,
265  const int cb) const
266  {
267  START_CODE();
268 
269  if( chi.size() != N5 ) chi.resize(N5);
270 
271  Real mass = ( Real(1) + m_q ) / (Real(1) - m_q);
272 
273 
274  int G5 = Ns*Ns-1;
275  Real ftmp;
276  Real ftmp2;
277  switch(isign) {
278  case PLUS :
279  {
280 
281  // [ A_0 B_0 0 ....... ]
282  // [ B_0 A_1 B_1 ....... ]
283  // [ 0 B_1 A_2 B_2 ....... ]
284  // [ ......................... B_N5-2]
285  // [ 0 B_N5-2 A_N5-1]
286  //
287  //
288  // WIth
289  // A[i] = beta_tilde[i] gamma_5 (-1/2) Dslash i < N5-1
290  // = Dslash^dagger [ (-1/2) gamma_5 beta_tilde[i] ]
291 
292  // A[N5-1] = mass*f_minus (-1/2) Dslash^dagger gamma_5
293  // + beta_tilde[N5-1] gamma_5 (-1/2) Dslash
294  // = Dslash^dagger [ (-1/2)gamma_g5{
295  // mass*f_minus + beta_tilde[N5-1] }
296 
297  // (beta_tilde has f_plus folded into it already)
298  //
299  // B_i = alpha_i * f_minus (-1/2) D^{\dagger}
300  // = D^{dagger} [ (-1/2)alpha_i*f_minus ]
301 
302  // Work everyhting out first. Apply D^dagger at the end.
303 
304 
305  multi1d<LatticeFermion> tmp5(N5);
306  moveToFastMemoryHint(tmp5);
307  Real coeff_1, coeff_2, coeff_3;
308  int otherCB = (cb + 1)%2;
309 
310  // First comomnent A_0 psi_0 + B_0 psi_1
311  //
312  // without D^dagger we get:
313  //
314  // [ (-1/2)gamma_g5 beta_tilde[0] psi_0 + (-1/2)alpha_0 f_minus psi_1 ]
315  // = (-1/2) [ gamma_g5 beta_tilde[0] psi_0 + alpha_0 f_minus_psi_1 ]
316 
317 
318 #if 0
319  tmp[rb[otherCB]] = Gamma(G5)*psi[0];
320  coeff_1 = Real(-0.5)*beta_tilde[0];
321  coeff_2 = Real(-0.5)*alpha[0]*f_minus;
322 
323  tmp5[0][rb[otherCB]] = coeff_1*tmp + coeff_2*psi[1];
324 #else
325  coeff_1 = Real(-0.5)*beta_tilde[0];
326  coeff_2 = Real(-0.5)*alpha[0]*f_minus;
327 
328  // 6NcNs flops
329  tmp5[0][rb[otherCB]] = coeff_2*psi[1] + coeff_1*(GammaConst<Ns,Ns*Ns-1>()*psi[0]);
330 #endif
331  // N5-2*(10NcNs)
332  for(int i=1; i < N5-1; i++) {
333 
334  // i=1 .. N5-2
335  //
336  // B_{i-1} psi_{i-1} + A_i psi_i + B_{i} psi_{i+1}
337  // (-1/2)alpha_{i-1} f_minus psi_{i-1}
338  // + (-1/2)alpha_{i} f_minus psi_{i+1}
339  // + (-1/2)gamma_g5 beta_tilde[i] psi_i
340  coeff_1 = Real(-0.5)*alpha[i-1]*f_minus;
341  coeff_2 = Real(-0.5)*alpha[i]*f_minus;
342  coeff_3 = Real(-0.5)*beta_tilde[i];
343  // tmp[rb[otherCB]] = Gamma(G5)*psi[i];
344 
345  tmp5[i][rb[otherCB]] = coeff_1*psi[i-1] + coeff_3*(GammaConst<Ns,Ns*Ns-1>()*psi[i]);
346  //tmp5[i][rb[otherCB]] += coeff_3*tmp;
347  tmp5[i][rb[otherCB]] += coeff_2*psi[i+1];
348  }
349 
350  // i=N5-1
351  //
352  // B_{i-1} psi_{i-1} + A_[N5-1] psi_[N5-1]
353  // B_{i-1} psi_{i-1} = (-1/2) alpha[N5-1]*f_minus
354 
355  // A_[N5-1] psi[N5-1] = (-1/2)gamma_g5{
356  // mass*f_minus + beta_tilde[N5-1] }
357  coeff_1 = Real(-0.5)*alpha[N5-2]*f_minus;
358  coeff_2 = Real(-0.5)*(mass*f_minus + beta_tilde[N5-1]);
359  //tmp[rb[otherCB]] = Gamma(G5)*psi[N5-1];
360 
361  // 6NcNs
362  tmp5[N5-1][rb[otherCB]] = coeff_1 * psi[N5-2] + coeff_2*(GammaConst<Ns,Ns*Ns-1>()*psi[N5-1]);
363 
364  // Now apply Dslash^{DAGGER} !!!!!
365  //
366  // (the dagger comes from the denominator. Along the diagonal
367  // we have gamma_5 D = D^{dagger} gamma_g5
368  // This could be done with a vec op.
369  // Alternatively, I could infuse it with other loops
370  // don't know what's best.
371  // for(int i=0; i < N5; i++) {
372  // Dslash->apply(chi[i], tmp5[i], MINUS, cb);
373  //}
374  Dslash.apply(chi,tmp5,MINUS, cb);
375 
376  }
377  break;
378 
379  case MINUS:
380  {
381  multi1d<LatticeFermion> D_psi(N5); moveToFastMemoryHint(D_psi);
382  Real ftmp_mhalf = Real(-0.5);
383 
384  Dslash.apply(D_psi, psi, PLUS, cb);
385 
386  for(int i=0; i < N5; i++) {
387  // Do I need this? D_psi[i] = zero; Seemingly not!
388 
389  // Dslash.apply(D_psi[i], psi[i], PLUS, cb);
390  D_psi[i][rb[cb]] *= ftmp_mhalf;
391  }
392 
393  // First bit
394  // Bits involving beta_tilde are hermitian and do not change
395  // chi[0][rb[cb]] = Gamma(G5)*D_psi[0];
396  // chi[0][rb[cb]] *= beta_tilde[0];
397  ftmp = alpha[0]*f_minus;
398  chi[0][rb[cb]] = ftmp*D_psi[1] + beta_tilde[0]*(GammaConst<Ns,Ns*Ns-1>()*D_psi[0]);
399 
400  for(int i=1; i < N5-1; i++) {
401 
402  ftmp = alpha[i-1]*f_minus;
403  ftmp2 = alpha[i]*f_minus;
404  chi[i][rb[cb]] = ftmp*D_psi[i-1] + beta_tilde[i]*(GammaConst<Ns,Ns*Ns-1>()*D_psi[i]);
405 
406  // ftmp = beta_tilde[i];
407  // tmp[rb[cb]] = Gamma(G5)*D_psi[i];
408  // chi[i][rb[cb]] += ftmp*tmp;
409 
410 
411  chi[i][rb[cb]] += ftmp2*D_psi[i+1];
412 
413  }
414 
415  // tmp[rb[cb]] = Gamma(G5) * D_psi[N5-1];
416  ftmp = mass*f_minus;
417  ftmp2 = alpha[N5-2]*f_minus;
418  chi[N5-1][rb[cb]] = ftmp2*D_psi[N5-2] + ftmp*(GammaConst<Ns,Ns*Ns-1>()*D_psi[N5-1]);
419 
420 
421 
422 
423  if( !isLastZeroP ) {
424  LatticeFermion tmp; moveToFastMemoryHint(tmp);
425  tmp[rb[cb]] = beta_tilde[N5-1]*(GammaConst<Ns,Ns*Ns-1>()*D_psi[N5-1]);
426  chi[N5-1][rb[cb]] += tmp;
427  }
428 
429 
430 
431  }
432  break;
433  default:
434  {
435  QDPIO::cerr << "Should never reach here. Isign is only 2 valued" << std::endl;
436  QDP_abort(1);
437  }
438  break;
439  }
440 
441  END_CODE();
442  }
443 
444 
445  // Derivative of even-odd linop component
446  /*
447  * This is a copy of the above applyOffDiag with the D.apply(...) replaced
448  * by D.deriv(ds_tmp,...) like calls.
449  */
450  void
451  EvenOddPrecHtContFrac5DLinOpArray::applyDerivOffDiag(multi1d<LatticeColorMatrix>& ds_u,
452  const multi1d<LatticeFermion>& chi,
453  const multi1d<LatticeFermion>& psi,
454  enum PlusMinus isign,
455  int cb) const
456  {
457  START_CODE();
458 
459 #if 0
460  ds_u.resize(Nd);
461  ds_u = zero;
462 
463  multi1d<LatticeColorMatrix> ds_tmp(Nd);
464 
465  LatticeFermion tmp; moveToFastMemoryHint(tmp);
466  Real coeff;
467  int G5 = Ns*Ns-1;
468 
469  switch (isign)
470  {
471  case PLUS:
472  // Optimisation... do up to the penultimate block...
473  for(int i=0; i < N5; i++)
474  {
475  if (i == N5-1 && isLastZeroP) continue;
476 
477  // CB is CB of TARGET
478  // consider case of gamma_5 Dslash
479  tmp[rb[cb]] = Gamma(G5)*chi[i];
480 
481  // Multiply coefficient
482  coeff = -Real(0.5)*beta_tilde[i];
483 
484  // Chi_i is now -(1/2) beta_tilde_i Dslash
485  tmp[rb[cb]] *= coeff;
486 
487  // Apply g5 Dslash
488  Dslash.deriv(ds_tmp, tmp, psi[i], PLUS, cb);
489  ds_u += ds_tmp;
490  }
491  break;
492 
493  case MINUS:
494  // Optimisation... do up to the penultimate block...
495  for(int i=0; i < N5; i++)
496  {
497  if (i == N5-1 && isLastZeroP) continue;
498 
499  // CB is CB of TARGET
500  // consider case of Dslash^dag gamma_5
501  tmp[rb[1-cb]] = Gamma(G5)*psi[i];
502 
503  // Multiply coefficient
504  coeff = -Real(0.5)*beta_tilde[i];
505 
506  // Chi_i is now -(1/2) beta_tilde_i Dslash
507  tmp[rb[1-cb]] *= coeff;
508 
509  // Apply g5 Dslash
510  Dslash.deriv(ds_tmp, chi[i], tmp, MINUS, cb);
511  ds_u += ds_tmp;
512  }
513  break;
514 
515  default:
516  QDP_error_exit("unknown case");
517  }
518 
519 #else
520  QDPIO::cerr << "NOt yet implemented " << std::endl;
521  QDP_abort(1);
522 #endif
523 
524  getFermBC().zero(ds_u);
525 
526  END_CODE();
527  }
528 
529 } // End Namespace Chroma
530 
531 
Primary include file for CHROMA library code.
void applyDerivOffDiag(multi1d< LatticeColorMatrix > &ds_u, const multi1d< LatticeFermion > &chi, const multi1d< LatticeFermion > &psi, enum PlusMinus isign, int cb) const
Apply the even-odd (odd-even) coupling piece of the NEF operator.
void applyOffDiag(multi1d< LatticeFermion > &chi, const multi1d< LatticeFermion > &psi, enum PlusMinus isign, const int cb) const
Apply the off diagonal block.
const FermBC< T, P, Q > & getFermBC() const
Return the fermion BC object for this linear operator.
Support class for fermion actions and linear operators.
Definition: state.h:94
Class for counted reference semantics.
Definition: handle.h:33
virtual void deriv(multi1d< LatticeColorMatrix > &ds_u, const multi1d< LatticeFermion > &chi, const multi1d< LatticeFermion > &psi, enum PlusMinus isign) const
Take deriv of D.
Include possibly optimized Wilson dslash.
Unpreconditioned extended-Overlap (5D) (Naryanan&Neuberger) linear operator.
void apply(multi1d< LatticeFermion > &chi, const multi1d< LatticeFermion > &psi, enum PlusMinus isign, int cb) const
General Wilson-Dirac dslash.
void create(Handle< FermState< T, P, Q > > state, int N5_)
Creation routine.
void applyDiagInv(multi1d< LatticeFermion > &chi, const multi1d< LatticeFermion > &psi, enum PlusMinus isign, const int cb) const
Apply the inverse even-even (odd-odd) coupling piece of the domain-wall fermion operator.
void applyDiag(multi1d< LatticeFermion > &chi, const multi1d< LatticeFermion > &psi, enum PlusMinus isign, const int cb) const
Apply the even-even (odd-odd) coupling piece of the domain-wall fermion operator.
int y
Definition: meslate.cc:35
Nd
Definition: meslate.cc:74
static const LatticeInteger & beta(const int dim)
Definition: stag_phases_s.h:47
static const LatticeInteger & alpha(const int dim)
Definition: stag_phases_s.h:43
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
LatticeFermion tmp
Definition: mespbg5p_w.cc:36
int i
Definition: pbg5p_w.cc:55
Double mass
Definition: pbg5p_w.cc:54
@ MINUS
Definition: chromabase.h:45
@ PLUS
Definition: chromabase.h:45
multi1d< LatticeFermion > chi(Ncb)
LatticeFermion psi
Definition: mespbg5p_w.cc:35
START_CODE()
int cb
Definition: invbicg.cc:120
Double zero
Definition: invbicg.cc:106
Double ftmp2
Definition: topol.cc:30