CHROMA
clover_term_base_w.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /*! \file
3  * \brief Clover term linear operator
4  */
5 
6 #ifndef __clover_term_base_w_h__
7 #define __clover_term_base_w_h__
8 
9 #include "chroma_config.h"
10 #include "linearop.h"
11 
12 
13 namespace Chroma
14 {
15  //! Clover term
16  /*!
17  * \ingroup linop
18  *
19  */
20 
21  template<typename T, typename U>
23  multi1d<U>,
24  multi1d<U> >
25  {
26  public:
27  //! No real need for cleanup here
28  virtual ~CloverTermBase() {}
29 
30  //! Subset is all here
31  const Subset& subset() const {return all;}
32 
33 
34  virtual void applySite(T& chi, const T& psi, enum PlusMinus isign, int site) const = 0;
35 
36  //! Invert
37  /*!
38  * Computes the inverse of the term on cb using Cholesky
39  */
40  virtual void choles(int cb) = 0;
41 
42  //! Invert
43  /*!
44  * Computes the determinant of the term
45  *
46  * \return logarithm of the determinant
47  */
48  virtual Double cholesDet(int cb) const = 0;
49 
50  //! Take deriv of D
51  /*!
52  * \param chi left std::vector (Read)
53  * \param psi right std::vector (Read)
54  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
55  *
56  * \return Computes \f$chi^\dag * \dot(D} * psi\f$
57  */
58  void deriv(multi1d<U>& ds_u,
59  const T& chi, const T& psi,
60  enum PlusMinus isign) const;
61 
62  //! Take deriv of D
63  /*!
64  * \param chi left std::vector on cb (Read)
65  * \param psi right std::vector on 1-cb (Read)
66  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
67  * \param cb Checkerboard of chi std::vector (Read)
68  *
69  * \return Computes \f$chi^\dag * \dot(D} * psi\f$
70  */
71  void deriv(multi1d<U>& ds_u,
72  const T& chi, const T& psi,
73  enum PlusMinus isign, int cb) const;
74 
75  //! Take deriv of D
76  /*!
77  * \param chi left vectors (Read)
78  * \param psi right vectors (Read)
79  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
80  * \param cb Checkerboard of chi std::vector (Read)
81  *
82  * \return Computes \f$chi^\dag * \dot(D} * psi\f$
83  */
84  void derivMultipole(multi1d<U>& ds_u,
85  const multi1d<T>& chi, const multi1d<T>& psi,
86  enum PlusMinus isign) const;
87 
88  //! Take deriv of D
89  /*!
90  * \param chi left vectors on cb (Read)
91  * \param psi right vectors on cb (Read)
92  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
93  * \param cb Checkerboard of chi std::vector (Read)
94  *
95  * \return Computes \f$chi^\dag * \dot(D} * psi\f$
96  */
97 
98  void derivMultipole(multi1d<U>& ds_u,
99  const multi1d<T>& chi, const multi1d<T>& psi,
100  enum PlusMinus isign, int cb) const;
101 
102 
103  //! Take derivative of TrLn D
104  void derivTrLn(multi1d<U>& ds_u,
105  enum PlusMinus isign, int cb) const;
106 
107 
108  void deriv_loops(const int u, const int mu, const int cb,
109  U& ds_u_mu,
110  U& ds_u_nu,
111  const U& Lambda) const;
112 
113  //! Return flops performed by the operator()
114  unsigned long nFlops() const;
115 
116  //! Calculates Tr_D ( Gamma_mat L )
117  virtual void triacntr(U& B, int mat, int cb) const = 0;
118 
119  protected:
120 
121  //! Get the u field
122  virtual const multi1d<U>& getU() const = 0;
123 
124  //! get the clover coefficient
125  virtual Real getCloverCoeff(int mu, int nu) const = 0;
126 
127  };
128 
129  //! Return flops performed by the operator()
130  template<typename T, typename U>
131  unsigned long
132  CloverTermBase<T,U>::nFlops() const {return 552;}
133 
134 
135  //! Take deriv of D
136  /*!
137  * \param chi left std::vector (Read)
138  * \param psi right std::vector (Read)
139  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
140  *
141  * \return Computes \f$\chi^\dag * \dot(D} * \psi\f$
142  */
143  template<typename T, typename U>
144  void CloverTermBase<T,U>::deriv(multi1d<U>& ds_u,
145  const T& chi, const T& psi,
146  enum PlusMinus isign) const
147  {
148  START_CODE();
149 
150  // base deriv resizes.
151  // Even even checkerboard
152  deriv(ds_u, chi, psi, isign,0);
153 
154  // Odd Odd checkerboard
155  multi1d<U> ds_tmp;
156  deriv(ds_tmp, chi, psi, isign,1);
157 
158  ds_u += ds_tmp;
159 
160  END_CODE();
161  }
162 
163  template<typename T, typename U>
164  void CloverTermBase<T,U>::derivMultipole(multi1d<U>& ds_u,
165  const multi1d<T>& chi, const multi1d<T>& psi,
166  enum PlusMinus isign) const
167  {
168  START_CODE();
169 
170  // base deriv resizes.
171  // Even even checkerboard
172  derivMultipole(ds_u, chi, psi, isign,0);
173 
174  // Odd Odd checkerboard
175  multi1d<U> ds_tmp;
176  derivMultipole(ds_tmp, chi, psi, isign,1);
177 
178  ds_u += ds_tmp;
179 
180  END_CODE();
181  }
182 
183 
184 
185 #if defined(CHROMA_FUSED_CLOVER_DERIV_LOOPS) && !defined(BUILD_JIT_CLOVER_TERM)
186  /* Fused Deriv Loops code contributed by Jacques Block of Regensburg University */
187 #warning "Using Fused deriv_loops contributed by Jacques Bloch of Regensburg University"
188  template<typename LCM>
189  inline
190  void fused_deriv_loops(const multi1d<LCM>& u,
191  const int mu, const int nu, const int cb,
192  LCM& ds_u_mu, LCM& ds_u_nu, const LCM& Lambda)
193  {
194  // shifted input
195  LCM tmp;
196 
197  LCM Lambda_xplus_mu;
198  Lambda_xplus_mu = shift(Lambda, FORWARD, mu);
199 
200  // output to be shifted
201  LCM ds_tmp_mu;
202  LCM ds_tmp_nu;
203 
204  LCM u_nu_for_mu;
205  u_nu_for_mu = shift(u[nu],FORWARD, mu);
206  LCM u_mu_for_nu;
207  u_mu_for_nu = shift(u[mu],FORWARD, nu);
208 
209  using MatSU3 = PColorMatrix< RComplex< typename WordType<LCM>::Type_t>, 3>;
210 #define _elem(x,i) (x.elem(i).elem())
211 
212  MatSU3 staple_for;
213  MatSU3 staple_back;
214  MatSU3 staple_left;
215  MatSU3 staple_right;
216 
217  MatSU3 u_tmp3;
218  MatSU3 up_left_corner;
219  MatSU3 up_right_corner;
220  MatSU3 low_right_corner;
221  MatSU3 low_left_corner;
222 
223  // EVEN
224  {
225  const Subset &s=rb[cb];
226  const int* tab = s.siteTable().slice();
227  const int numSiteTable = s.numSiteTable();
228  LCM &Lambda_xplus_muplusnu=tmp;
229  Lambda_xplus_muplusnu[s] = shift(Lambda_xplus_mu, FORWARD, nu);
230 
231 #pragma omp parallel for private(staple_for, staple_back, staple_left, staple_right, u_tmp3, up_left_corner, up_right_corner, low_right_corner, low_left_corner)
232  for(int j=0; j < numSiteTable; ++j)
233  {
234  int i = tab[j];
235 
236  up_left_corner = adj(_elem(u_mu_for_nu,i))*adj(_elem(u[nu],i));
237  low_right_corner = adj(_elem(u_nu_for_mu,i))*adj(_elem(u[mu],i));
238  low_left_corner = adj(_elem(u[mu],i))*_elem(u[nu],i);
239 
240  u_tmp3 = _elem(u_nu_for_mu,i)*_elem(Lambda_xplus_muplusnu,i);
241  _elem(ds_u_mu,i) = u_tmp3*up_left_corner;
242 
243  u_tmp3 = up_left_corner*_elem(Lambda,i);
244  _elem(ds_tmp_nu,i) = u_tmp3*_elem(u[mu],i);
245 
246  u_tmp3 = low_right_corner*_elem(Lambda,i);
247  _elem(ds_tmp_mu,i) = u_tmp3*_elem(u[nu],i);
248 
249  u_tmp3 = _elem(u_mu_for_nu,i)*_elem(Lambda_xplus_muplusnu,i);
250  _elem(ds_u_nu,i) = u_tmp3*low_right_corner;
251 
252  staple_for = _elem(u_nu_for_mu,i)*up_left_corner;
253  staple_right = up_left_corner*_elem(u[mu],i);
254  staple_left = _elem(u_mu_for_nu,i)*low_right_corner;
255  staple_back = adj(_elem(u_nu_for_mu,i))*low_left_corner;
256 
257  _elem(ds_u_mu,i) += staple_for*_elem(Lambda,i);
258  _elem(ds_tmp_nu,i) += _elem(Lambda_xplus_muplusnu,i)*staple_right;
259  _elem(ds_u_nu,i) += staple_left*_elem(Lambda,i);
260  _elem(ds_tmp_mu,i) += _elem(Lambda_xplus_muplusnu,i)*staple_back;
261  }
262  }
263 
264  // ODD
265  {
266  const Subset &s=rb[1-cb];
267  const int* tab = s.siteTable().slice();
268  const int numSiteTable = s.numSiteTable();
269 
270  LCM &Lambda_xplus_nu=tmp;
271  Lambda_xplus_nu[s] = shift(Lambda, FORWARD, nu);
272 
273 #pragma omp parallel for private(staple_for, staple_back, staple_left, staple_right, u_tmp3, up_left_corner, up_right_corner, low_right_corner, low_left_corner)
274  for (int j=0; j < numSiteTable; ++j)
275  {
276  int i = tab[j];
277 
278  up_left_corner = adj(_elem(u_mu_for_nu,i))*adj(_elem(u[nu],i));
279  up_right_corner = _elem(u_nu_for_mu,i)*adj(_elem(u_mu_for_nu,i));
280  low_right_corner = adj(_elem(u_nu_for_mu,i))*adj(_elem(u[mu],i));
281  low_left_corner = adj(_elem(u[mu],i))*_elem(u[nu],i);
282 
283  u_tmp3 = adj(_elem(u_mu_for_nu,i))*_elem(Lambda_xplus_nu,i);
284  _elem(ds_tmp_nu,i) = u_tmp3*adj(low_left_corner);
285 
286  u_tmp3 = _elem(Lambda_xplus_nu,i)*adj(_elem(u[nu],i));
287  _elem(ds_u_mu,i) = up_right_corner * u_tmp3;
288 
289  u_tmp3 = adj(_elem(u_nu_for_mu,i))*_elem(Lambda_xplus_mu,i);
290  _elem(ds_tmp_mu,i) = u_tmp3*low_left_corner;
291 
292  u_tmp3 = adj(up_right_corner)*_elem(Lambda_xplus_mu,i);
293  _elem(ds_u_nu,i) = u_tmp3*adj(_elem(u[mu],i));
294 
295  staple_for = _elem(u_nu_for_mu,i)*up_left_corner;
296  staple_right = up_left_corner*_elem(u[mu],i);
297  staple_left = _elem(u_mu_for_nu,i)*low_right_corner;
298  staple_back = adj(_elem(u_nu_for_mu,i))*low_left_corner;
299 
300  _elem(ds_tmp_nu,i) += staple_right*_elem(Lambda_xplus_mu,i);
301  _elem(ds_u_mu,i) += _elem(Lambda_xplus_mu,i)*staple_for;
302  _elem(ds_tmp_mu,i) += staple_back*_elem(Lambda_xplus_nu,i);
303  _elem(ds_u_nu,i) += _elem(Lambda_xplus_nu,i)*staple_left;
304  }
305  }
306 
307  // Now shift the accumulated pieces to mu and nu
308  //
309  // Hope that this is not too slow as an expression
310  ds_u_mu -= shift(ds_tmp_mu, BACKWARD, nu);
311  ds_u_nu -= shift(ds_tmp_nu, BACKWARD, mu);
312 #undef _elem
313 
314  END_CODE();
315 
316  }
317 #endif
318 
319  template<typename T, typename U>
320  void CloverTermBase<T,U>::deriv_loops(const int mu, const int nu, const int cb,
321  U& ds_u_mu,
322  U& ds_u_nu,
323  const U& Lambda) const
324  {
325  START_CODE();
326 
327  const multi1d<U>& u = getU();
328 
329 #if defined(CHROMA_FUSED_CLOVER_DERIV_LOOPS) && !defined(BUILD_JIT_CLOVER_TERM)
330  // Code from Jacques
331  fused_deriv_loops<U>(u,mu,nu,cb,ds_u_mu,ds_u_nu,Lambda);
332 
333 #else
334  // New thingie - now assume Lambda lives only on sites with checkerboard
335  // CB
336  // Lambda
337  // 0 X 0 x = cb, O = 1-cb
338  //
339  //
340  // Lambda Lambda
341  // X 0 X
342  //
343  //
344  // Lambda
345  // 0 X 0
346  //
347  // So I can only construct 4 out of the 8 staples on the sites
348  // that have CB and the OTHER 4 of the 8 staples on sites with
349  // 1-cb
350  //
351 
352  // Sites with CB first:
353  //
354 
355  U staple_for;
356  U staple_back;
357  U staple_left;
358  U staple_right;
359 
360  U u_nu_for_mu = shift(u[nu],FORWARD, mu); // Can reuse these later
361  U u_mu_for_nu = shift(u[mu],FORWARD, nu);
362  U Lambda_xplus_mu = shift(Lambda, FORWARD, mu);
363  U Lambda_xplus_nu = shift(Lambda, FORWARD, nu);
364  U Lambda_xplus_muplusnu = shift(Lambda_xplus_mu, FORWARD, nu);
365 
366  U u_tmp3;
367 
368  U ds_tmp_mu;
369  U ds_tmp_nu;
370  {
371  U up_left_corner;
372  U up_right_corner;
373  U low_right_corner;
374  U low_left_corner;
375 
376  // u_tmp1 = <-------
377  // |
378  // | ON ALL CHECKERBOARDS
379  // | (Because it's used in staples)
380  // V
381  up_left_corner = adj(u_mu_for_nu)*adj(u[nu]);
382 
383 
384  //
385  // <------^
386  // |
387  // |
388  // |
389 
390  up_right_corner = u_nu_for_mu*adj(u_mu_for_nu);
391 
392  // |
393  // |
394  // |
395  // V
396  // <------
397  low_right_corner = adj(u_nu_for_mu)*adj(u[mu]);
398 
399  //
400  // ^
401  // low left corner= | ON ALL CHECKBERBOARDS
402  // | (Because it's used in the staples)
403  // |
404  // <-------
405  low_left_corner = adj(u[mu])*u[nu];
406 
407 
408  // Now compute the terms of the force:
409  //
410  // Altogether 8 terms. 4 Upwards with + sign, and 4 Downwards with - sign
411  // 4 terms use staples and 4 don't
412 
413  // NON STAPLE TERMS FIRST:
414 
415  // 1) mu links
416  //
417  // <------- X (CB) <--------
418  // | ^ |
419  // | | re use u_tmp1 = |
420  // V | V
421  // CB 1-CB
422  u_tmp3[rb[cb]] = u_nu_for_mu*Lambda_xplus_muplusnu;
423  ds_u_mu[rb[cb]] = u_tmp3*up_left_corner;
424 
425  // nu links
426  // X
427  // <------
428  // |
429  // |
430  // |
431  // V-----> CB
432  // (1-CB)
433  //
434  u_tmp3[rb[1-cb]] = adj(u_mu_for_nu)*Lambda_xplus_nu;
435 
436  // accumulate into ds_tmp_nu and shift everything together at the end
437  ds_tmp_nu[rb[1-cb]] = u_tmp3*adj(low_left_corner);
438 
439 
440 
441  // 2) mu links
442  //
443  // CB
444  // X <------
445  // | ^ re use u[nu](x+mu) = u_nu_for_mu
446  // | | re use u[mu](x+nu) = u_mu_for_nu
447  // V |
448  // 1-CB CB
449  u_tmp3[rb[1-cb]] = Lambda_xplus_nu*adj(u[nu]);
450  ds_u_mu[rb[1-cb]] = up_right_corner * u_tmp3;
451 
452  // nu_links
453  //
454  // <------
455  // |
456  // |
457  // |
458  // X V----->1-CB
459  // (CB)
460  //
461  u_tmp3[rb[cb]] = up_left_corner*Lambda;
462  //
463  // accumulate into ds_tmp_nu and shift everything together at the end
464  ds_tmp_nu[rb[cb]] = u_tmp3*u[mu];
465 
466 
467 
468 
469  //
470  // Terms 3) and 4)
471  //
472  // These last two can be done on the other checkerboard and then shifted together. at the very end...
473  //
474  // CB 1-CB
475  // ^ |
476  // | |
477  // | V
478  // <-------X CB
479 
480 
481  // 3) Mu links
482  //
483  // Compunte with low_left_corner: ^ |
484  // | |
485  // low_left_corner = | |
486  // | V
487  // (1-CB) <-------- X CB
488  u_tmp3[rb[1-cb]] = adj(u_nu_for_mu)*Lambda_xplus_mu;
489  //
490  // accumulate into ds_tmp_mu and shift at the end.
491  ds_tmp_mu[rb[1-cb]] = u_tmp3*low_left_corner;
492 
493  // Nu links
494  //
495  // CB ------> ------->
496  // | |
497  // | reuse adj(up_right_corner): |
498  // | |
499  // V V
500  // 1-CB <------X
501  u_tmp3[rb[1-cb]] = adj(up_right_corner)*Lambda_xplus_mu;
502  ds_u_nu[rb[1-cb]] = u_tmp3*adj(u[mu]);
503 
504 
505 
506  // 4) Mu links
507  //
508  // 1-CB CB
509  // ^ |
510  // | | reuse = u[nu](x+mu) = u_nu_for_mu
511  // | |
512  // X <----- V 1-CB
513  // CB
514  u_tmp3[rb[cb]] = low_right_corner*Lambda;
515  //
516  // accumulate into ds_tmp_mu and shift at the end.
517  ds_tmp_mu[rb[cb]] = u_tmp3*u[nu];
518 
519 
520 
521  // Nu links
522  //
523  // 1-CB ------> X
524  // | |
525  // | reuse low_right_corner: |
526  // | |
527  // V V
528  // CB <------ <------
529  u_tmp3[rb[cb]] = u_mu_for_nu*Lambda_xplus_muplusnu;
530  ds_u_nu[rb[cb]] = u_tmp3*low_right_corner;
531 
532 
533  // ds_tmp_mu now holds the last 2 terms, one on each of its checkerboards, but Now I need
534  // to shift them both together onto ds_u_mu
535  // I'll keep them in ds_tmp_mu right, bearing in mind I'll need to bring
536  // them in with a -ve contribution...
537 
538 
539  // STAPLE TERMS:
540 
541  // Construct the staples
542 
543  // Staple_for = <--------
544  // | ^
545  // | | ON ALL CHECKERBOARDS
546  // | |
547  // V |
548  staple_for = u_nu_for_mu*up_left_corner;
549 
550 
551  // Staple_right = <----- ON ALL CHECKERBOARDS
552  // |
553  // |
554  // V
555  // ----->
556  staple_right = up_left_corner*u[mu];
557 
558 
559 
560  // ----->
561  // |
562  // |
563  // |
564  // <----- V
565  staple_left = u_mu_for_nu*low_right_corner;
566 
567 
568 
569 
570  // Staple_back = ^ |
571  // | | ON ALL CHECKERBOARDS
572  // | |
573  // <------ V
574  //
575  staple_back = adj(u_nu_for_mu)*low_left_corner;
576 
577  } // Corner pieces go away here
578 
579  // 5) Mu links
580  //
581  // <-------
582  // | ^
583  // | | use computed staple
584  // V |
585  // x
586  // CB 1-CB
587  ds_u_mu[rb[cb]] += staple_for*Lambda;
588 
589 
590  // Nu links
591  //
592  // CB <---- 1-CB
593  // |
594  // | use staple_right
595  // V
596  // 1-CB -----> X CB
597  //
598  // Accumulate into ds_tmp_nu and shift at the end.
599 
600  ds_tmp_nu[rb[1-cb]] += staple_right*Lambda_xplus_mu;
601 
602 
603  // 6) Mu links
604  //
605  // <-------
606  // | ^
607  // | | re use computed staple
608  // V |
609  // 1-CB X CB
610 
611  ds_u_mu[rb[1-cb]] += Lambda_xplus_mu*staple_for;
612 
613 
614 
615  // Nu links
616  //
617  // <---- X CB
618  // |
619  // | use adj(staple_right)
620  // |
621  // CB V ----> (1-CB)
622  ds_tmp_nu[rb[cb]] += Lambda_xplus_muplusnu * staple_right;
623 
624 
625  // 7) Mu links
626  //
627  // CB 1-CB
628  // X
629  // ^ |
630  // | | re use computed staple
631  // | |
632  // <-------V
633  //
634  // Accumulate into ds_tmp_mu and shift at the end.
635  ds_tmp_mu[rb[1-cb]] += staple_back*Lambda_xplus_nu;
636 
637  // Now for nu
638  //
639  // (1-CB) -----> CB use adj(staple_left)
640  // |
641  // |
642  // V
643  // CB X <----
644  //
645  ds_u_nu[rb[cb]] += staple_left*Lambda;
646 
647  // 8) Mu links
648  //
649  // 1-CB X CB
650  // ^ |
651  // | | reuse computed staple
652  // | |
653  // <-------V
654  //
655  // Accumulate into ds_tmp_mu and shift at the end
656  ds_tmp_mu[rb[cb]] += Lambda_xplus_muplusnu * staple_back;
657 
658  // Now for Nu
659  //
660  // CB X ------> (1-CB)
661  // |
662  // |
663  // |
664  // V
665  // 1-CB <------- CB
666  ds_u_nu[rb[1-cb]] += Lambda_xplus_nu * staple_left;
667 
668  // Now shift the accumulated pieces to mu and nu
669  //
670  // Hope that this is not too slow as an expression
671  ds_u_mu -= shift(ds_tmp_mu, BACKWARD, nu);
672  ds_u_nu -= shift(ds_tmp_nu, BACKWARD, mu);
673 
674 #endif
675 
676  END_CODE();
677  }
678 
679 
680 
681  //! Take deriv of D
682  /*!
683  * \param chi left std::vector on cb (Read)
684  * \param psi right std::vector on 1-cb (Read)
685  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
686  * \param cb Checkerboard of chi std::vector (Read)
687  *
688  * \return Computes \f$\chi^\dag * \dot(D} * \psi\f$
689  */
690  template<typename T, typename U>
691  void CloverTermBase<T,U>::deriv(multi1d<U>& ds_u,
692  const T& chi, const T& psi,
693  enum PlusMinus isign, int cb) const
694  {
695  START_CODE();
696 
697 
698  // Do I still need to do this?
699  if( ds_u.size() != Nd ) {
700  ds_u.resize(Nd);
701  }
702 
703  ds_u = zero;
704 
705  // Get the links
706  //const multi1d<U>& u = getU();
707 
708 
709  // Now compute the insertions
710  for(int mu=0; mu < Nd; mu++) {
711  for(int nu = mu+1; nu < Nd; nu++) {
712 
713  // These will be appropriately overwritten - no need to zero them.
714  // Contributions to mu links from mu-nu clover piece
715  U ds_tmp_mu;
716 
717  // -ve contribs to the nu_links from the mu-nu clover piece
718  // -ve because of the exchange of gamma_mu gamma_nu <-> gamma_nu gamma_mu
719  U ds_tmp_nu;
720 
721  // The weight for the terms
722  Real factor = (Real(-1)/Real(8))*getCloverCoeff(mu,nu);
723 
724  // Get gamma_mu gamma_nu psi -- no saving here, from storing shifts because
725  // I now only do every mu, nu pair only once.
726 
727  int mu_nu_index = (1 << mu) + (1 << nu); // 2^{mu} 2^{nu}
728  T ferm_tmp = Gamma(mu_nu_index)*psi;
729  U s_xy_dag = traceSpin( outerProduct(ferm_tmp,chi));
730  s_xy_dag *= Real(factor);
731 
732  // Compute contributions
733  deriv_loops(mu, nu, cb, ds_tmp_mu, ds_tmp_nu, s_xy_dag);
734 
735  // Accumulate them
736  ds_u[mu] += ds_tmp_mu;
737  ds_u[nu] -= ds_tmp_nu;
738 
739 
740  }
741  }
742 
743 
744  // Clear out the deriv on any fixed links
745  (*this).getFermBC().zero(ds_u);
746  END_CODE();
747  }
748 
749  template<typename T, typename U>
750  void CloverTermBase<T,U>::derivMultipole(multi1d<U>& ds_u,
751  const multi1d<T>& chi, const multi1d<T>& psi,
752  enum PlusMinus isign, int cb) const
753  {
754  // Multipole deriv
755  START_CODE();
756 
757  // Do I still need to do this?
758  if( ds_u.size() != Nd ) {
759  ds_u.resize(Nd);
760  }
761 
762  ds_u = zero;
763 
764  // Get the links
765  //const multi1d<U>& u = getU();
766 
767 
768  // Now compute the insertions
769  for(int mu=0; mu < Nd; mu++) {
770  for(int nu = mu+1; nu < Nd; nu++) {
771 
772  // These will be appropriately overwritten - no need to zero them.
773  // Contributions to mu links from mu-nu clover piece
774  U ds_tmp_mu;
775 
776  // -ve contribs to the nu_links from the mu-nu clover piece
777  // -ve because of the exchange of gamma_mu gamma_nu <-> gamma_nu gamma_mu
778  U ds_tmp_nu;
779 
780  // The weight for the terms
781  Real factor = (Real(-1)/Real(8))*getCloverCoeff(mu,nu);
782 
783  // Get gamma_mu gamma_nu psi -- no saving here, from storing shifts because
784  // I now only do every mu, nu pair only once.
785 
786  int mu_nu_index = (1 << mu) + (1 << nu); // 2^{mu} 2^{nu}
787 
788  // Accumulate all the trace spin outer products
789  U s_xy_dag = zero;
790  for(int i=0; i < chi.size(); i++) {
791  T ferm_tmp = Gamma(mu_nu_index)*psi[i];
792  s_xy_dag += traceSpin( outerProduct(ferm_tmp,chi[i]));
793  }
794 
795  s_xy_dag *= Real(factor);
796 
797  // Compute contributions
798  deriv_loops(mu, nu, cb, ds_tmp_mu, ds_tmp_nu, s_xy_dag);
799 
800  // Accumulate them
801  ds_u[mu] += ds_tmp_mu;
802  ds_u[nu] -= ds_tmp_nu;
803 
804 
805  }
806  }
807 
808 
809  // Clear out the deriv on any fixed links
810  (*this).getFermBC().zero(ds_u);
811  END_CODE();
812  }
813 
814 
815  //! Take deriv of D using Trace Log
816  /*!
817  * \param chi left std::vector on cb (Read)
818  * \param psi right std::vector on 1-cb (Read)
819  * \param isign D'^dag or D' ( MINUS | PLUS ) resp. (Read)
820  * \param cb Checkerboard of chi std::vector (Read)
821  *
822  * \return Computes \f$\chi^\dag * \dot(D} * \psi\f$
823  */
824  template<typename T, typename U>
825  void CloverTermBase<T,U>::derivTrLn(multi1d<U>& ds_u,
826  enum PlusMinus isign, int cb) const
827  {
828  START_CODE();
829 
830  // Do I still need to do this?
831  if( ds_u.size() != Nd ) {
832  ds_u.resize(Nd);
833  }
834 
835  ds_u = zero;
836 
837  for(int mu=0; mu < Nd; mu++) {
838  for(int nu = mu+1; nu < Nd; nu++) {
839 
840  // Index
841  int mu_nu_index = (1 << mu) + (1 << nu); // 2^{mu} 2^{nu}
842 
843  // The actual coefficient factor
844  Real factor = Real(-1)*getCloverCoeff(mu,nu)/Real(8);
845 
846  U sigma_XY_dag=zero;
847 
848  // Get weight*Tr_spin gamma_mu gamma_nu A^{-1} piece
849  triacntr(sigma_XY_dag, mu_nu_index, cb);
850  sigma_XY_dag[rb[cb]] *= factor;
851 
852  // These will be overwritten so no need to initialize to zero
853  U ds_tmp_mu;
854  U ds_tmp_nu;
855 
856  // Get contributions from the loops and insersions
857  deriv_loops(mu, nu, cb, ds_tmp_mu, ds_tmp_nu, sigma_XY_dag);
858 
859  // Accumulate
860  ds_u[mu] += ds_tmp_mu;
861  // -ve weight for nu from gamma_mu gamma_nu -> gamma_nu gamma_mu
862  // commutation.
863  ds_u[nu] -= ds_tmp_nu;
864 
865  } // End loop over nu
866 
867  } // end of loop over mu
868 
869 
870  // Not sure this is needed here, but will be sure
871  (*this).getFermBC().zero(ds_u);
872 
873  END_CODE();
874  }
875 
876 
877 
878 } // End Namespace Chroma
879 
880 
881 #endif
virtual void applySite(T &chi, const T &psi, enum PlusMinus isign, int site) const =0
virtual ~CloverTermBase()
No real need for cleanup here.
void derivMultipole(multi1d< U > &ds_u, const multi1d< T > &chi, const multi1d< T > &psi, enum PlusMinus isign, int cb) const
Take deriv of D.
void derivMultipole(multi1d< U > &ds_u, const multi1d< T > &chi, const multi1d< T > &psi, enum PlusMinus isign) const
Take deriv of D.
virtual void choles(int cb)=0
Invert.
unsigned long nFlops() const
Return flops performed by the operator()
void derivTrLn(multi1d< U > &ds_u, enum PlusMinus isign, int cb) const
Take derivative of TrLn D.
void deriv_loops(const int u, const int mu, const int cb, U &ds_u_mu, U &ds_u_nu, const U &Lambda) const
virtual Real getCloverCoeff(int mu, int nu) const =0
get the clover coefficient
virtual Double cholesDet(int cb) const =0
Invert.
void deriv(multi1d< U > &ds_u, const T &chi, const T &psi, enum PlusMinus isign, int cb) const
Take deriv of D.
const Subset & subset() const
Subset is all here.
void deriv(multi1d< U > &ds_u, const T &chi, const T &psi, enum PlusMinus isign) const
Take deriv of D.
virtual void triacntr(U &B, int mat, int cb) const =0
Calculates Tr_D ( Gamma_mat L )
virtual const multi1d< U > & getU() const =0
Get the u field.
Dslash-like Linear Operator.
Definition: linearop.h:221
int mu
Definition: cool.cc:24
int nu
Definition: cool.cc:25
unsigned j
Definition: ldumul_w.cc:35
Linear Operators.
Nd
Definition: meslate.cc:74
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
static multi1d< LatticeColorMatrix > u
LatticeFermion tmp
Definition: mespbg5p_w.cc:36
LinOpSysSolverMGProtoClover::T T
int i
Definition: pbg5p_w.cc:55
multi1d< LatticeFermion > chi(Ncb)
LatticeFermion psi
Definition: mespbg5p_w.cc:35
multi1d< LatticeColorMatrix > LCM
Definition: asqtad_qprop.cc:20
START_CODE()
int cb
Definition: invbicg.cc:120
Double zero
Definition: invbicg.cc:106
multi1d< LatticeFermion > s(Ncb)
FloatingPoint< double > Double
Definition: gtest.h:7351
#define FORWARD
Definition: primitives.h:82
#define BACKWARD
Definition: primitives.h:83
multi1d< LatticeColorMatrix > U
multi1d< LatticeColorMatrix > deriv(const EvenOddPrecLinearOperator< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > &AP, const LatticeFermion &chi, const LatticeFermion &psi, enum PlusMinus isign)
Apply the operator onto a source std::vector.
multi1d< LatticeColorMatrix > LCM
Definition: t_preccfz.cc:13