clover_term_base_w.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 // $Id: clover_term_base_w.h,v 3.8 2009/04/17 02:05:32 bjoo Exp $
00003 /*! \file
00004  *  \brief Clover term linear operator
00005  */
00006 
00007 #ifndef __clover_term_base_w_h__
00008 #define __clover_term_base_w_h__
00009 
00010 #include "linearop.h"
00011 
00012 
00013 namespace Chroma 
00014 { 
00015   //! Clover term
00016   /*!
00017    * \ingroup linop
00018    *
00019    */
00020 
00021   template<typename T, typename U>
00022            class CloverTermBase : public DslashLinearOperator<T,
00023                                                               multi1d<U>,
00024                                                               multi1d<U> >
00025   {
00026   public:
00027     //! No real need for cleanup here
00028     virtual ~CloverTermBase() {}
00029 
00030     //! Subset is all here
00031     const Subset& subset() const {return all;}
00032 
00033 
00034     virtual void applySite(T& chi, const T& psi, enum PlusMinus isign, int site) const = 0;
00035 
00036     //! Invert
00037     /*!
00038      * Computes the inverse of the term on cb using Cholesky
00039      */
00040     virtual void choles(int cb) = 0;
00041 
00042     //! Invert
00043     /*!
00044      * Computes the determinant of the term
00045      *
00046      * \return logarithm of the determinant  
00047      */
00048     virtual Double cholesDet(int cb) const = 0;
00049 
00050     //! Take deriv of D
00051     /*!
00052      * \param chi     left vector                                 (Read)
00053      * \param psi     right vector                                (Read)
00054      * \param isign   D'^dag or D'  ( MINUS | PLUS ) resp.        (Read)
00055      *
00056      * \return Computes   \f$chi^\dag * \dot(D} * psi\f$
00057      */
00058     void deriv(multi1d<U>& ds_u, 
00059                const T& chi, const T& psi, 
00060                enum PlusMinus isign) const;
00061 
00062     //! Take deriv of D
00063     /*!
00064      * \param chi     left vector on cb                           (Read)
00065      * \param psi     right vector on 1-cb                        (Read)
00066      * \param isign   D'^dag or D'  ( MINUS | PLUS ) resp.        (Read)
00067      * \param cb      Checkerboard of chi vector                  (Read)
00068      *
00069      * \return Computes   \f$chi^\dag * \dot(D} * psi\f$
00070      */
00071     void deriv(multi1d<U>& ds_u, 
00072                const T& chi, const T& psi, 
00073                enum PlusMinus isign, int cb) const;
00074 
00075     //! Take derivative of TrLn D
00076     void derivTrLn(multi1d<U>& ds_u, 
00077                    enum PlusMinus isign, int cb) const;
00078 
00079 
00080     void deriv_loops(const int u, const int mu, const int cb,
00081                      U& ds_u_mu,
00082                      U& ds_u_nu,
00083                      const U& Lambda) const;
00084 
00085     //! Return flops performed by the operator()
00086     unsigned long nFlops() const;
00087 
00088     //! Calculates Tr_D ( Gamma_mat L )
00089     virtual void triacntr(U& B, int mat, int cb) const = 0;
00090 
00091   protected:
00092 
00093     //! Get the u field
00094     virtual const multi1d<U>& getU() const = 0;
00095 
00096     //! get the clover coefficient 
00097     virtual Real getCloverCoeff(int mu, int nu) const = 0;
00098 
00099   };
00100 
00101   //! Return flops performed by the operator()
00102   template<typename T, typename U>
00103   unsigned long 
00104   CloverTermBase<T,U>::nFlops() const {return 552;}
00105 
00106 
00107   //! Take deriv of D
00108   /*!
00109    * \param chi     left vector                                 (Read)
00110    * \param psi     right vector                                (Read)
00111    * \param isign   D'^dag or D'  ( MINUS | PLUS ) resp.        (Read)
00112    *
00113    * \return Computes   \f$\chi^\dag * \dot(D} * \psi\f$
00114    */
00115   template<typename T, typename U>
00116   void CloverTermBase<T,U>::deriv(multi1d<U>& ds_u, 
00117                              const T& chi, const T& psi, 
00118                              enum PlusMinus isign) const
00119   {
00120     START_CODE();
00121 
00122     // base deriv resizes.
00123     // Even even checkerboard
00124     deriv(ds_u, chi, psi, isign,0);
00125     
00126     // Odd Odd checkerboard
00127     multi1d<U> ds_tmp;
00128     deriv(ds_tmp, chi, psi, isign,1);
00129     
00130     ds_u += ds_tmp;
00131     
00132     END_CODE();
00133   }
00134 
00135 
00136 
00137   template<typename T, typename U>
00138   void CloverTermBase<T,U>::deriv_loops(const int mu, const int nu, const int cb,
00139                                    U& ds_u_mu,
00140                                    U& ds_u_nu,
00141                                    const U& Lambda) const
00142   {
00143     START_CODE();
00144 
00145     const multi1d<U>& u = getU();
00146 
00147     // New thingie - now assume Lambda lives only on sites with checkerboard 
00148     // CB
00149     //            Lambda
00150     //   0           X           0           x = cb, O = 1-cb
00151     //
00152     //
00153     // Lambda                 Lambda 
00154     //   X           0           X
00155     //
00156     //
00157     //            Lambda 
00158     //   0           X           0
00159     //
00160     // So I can only construct 4 out of the 8 staples on the sites
00161     // that have CB and the OTHER 4 of the 8 staples on sites with 
00162     // 1-cb
00163     //
00164     
00165     // Sites with CB first:
00166     //
00167 
00168     U staple_for;
00169     U staple_back;
00170     U staple_left;
00171     U staple_right;
00172 
00173     U u_nu_for_mu = shift(u[nu],FORWARD, mu); // Can reuse these later
00174     U u_mu_for_nu = shift(u[mu],FORWARD, nu);
00175     U Lambda_xplus_mu = shift(Lambda, FORWARD, mu);
00176     U Lambda_xplus_nu = shift(Lambda, FORWARD, nu);
00177     U Lambda_xplus_muplusnu = shift(Lambda_xplus_mu, FORWARD, nu);
00178 
00179     U u_tmp3;
00180 
00181     U ds_tmp_mu;
00182     U ds_tmp_nu;
00183     {
00184       U up_left_corner;
00185       U up_right_corner;
00186       U low_right_corner;
00187       U low_left_corner;
00188 
00189       //   u_tmp1 =   <-------
00190       //              |
00191       //              |                       ON ALL CHECKERBOARDS
00192       //              |                       (Because it's used in staples)  
00193       //              V
00194       up_left_corner = adj(u_mu_for_nu)*adj(u[nu]);
00195       
00196       
00197       //
00198       //              <------^
00199       //                     |
00200       //                     |
00201       //                     |
00202       
00203       up_right_corner = u_nu_for_mu*adj(u_mu_for_nu);
00204       
00205       //                       |
00206       //                       |
00207       //                       |
00208       //                       V
00209       //                <------
00210       low_right_corner = adj(u_nu_for_mu)*adj(u[mu]);
00211       
00212       //
00213       //                    ^
00214       //  low left corner=  |                         ON ALL CHECKBERBOARDS
00215       //                    |                         (Because it's used in the staples)
00216       //                    |  
00217       //                     <-------
00218       low_left_corner = adj(u[mu])*u[nu];
00219       
00220       
00221       // Now compute the terms of the force:
00222       // 
00223       // Altogether 8 terms. 4 Upwards with + sign, and 4 Downwards with - sign
00224       //                     4 terms use staples and 4 don't
00225       
00226       // NON STAPLE TERMS FIRST:
00227       
00228       // 1) mu links
00229       //
00230       //    <-------  X (CB)                      <--------
00231       //    |         ^                           |
00232       //    |         |        re  use  u_tmp1 =  | 
00233       //    V         |                           V
00234       //   CB       1-CB       
00235       u_tmp3[rb[cb]] = u_nu_for_mu*Lambda_xplus_muplusnu;
00236       ds_u_mu[rb[cb]] = u_tmp3*up_left_corner;
00237       
00238       //    nu links
00239       //    X
00240       //     <------
00241       //     | 
00242       //     |
00243       //     |
00244       //     V-----> CB
00245       //   (1-CB)   
00246       //
00247       u_tmp3[rb[1-cb]] = adj(u_mu_for_nu)*Lambda_xplus_nu;
00248       
00249       // accumulate into ds_tmp_nu and shift everything together at the end
00250       ds_tmp_nu[rb[1-cb]] = u_tmp3*adj(low_left_corner);
00251       
00252       
00253       
00254       // 2)  mu links
00255       //
00256       //  CB
00257       //    X <------ 
00258       //    |        ^       re use u[nu](x+mu) = u_nu_for_mu
00259       //    |        |       re use u[mu](x+nu) = u_mu_for_nu
00260       //    V        |
00261       //    1-CB    CB        
00262       u_tmp3[rb[1-cb]] = Lambda_xplus_nu*adj(u[nu]);
00263       ds_u_mu[rb[1-cb]] = up_right_corner * u_tmp3;
00264       
00265       //      nu_links
00266       //    
00267       //     <------
00268       //     | 
00269       //     |
00270       //     |
00271       //   X V----->1-CB
00272       //   (CB)   
00273       //
00274       u_tmp3[rb[cb]] = up_left_corner*Lambda;
00275       //
00276       // accumulate into ds_tmp_nu and shift everything together at the end
00277       ds_tmp_nu[rb[cb]] = u_tmp3*u[mu];
00278       
00279       
00280       
00281       
00282       //
00283       // Terms 3) and 4)
00284       //
00285       // These last two can be done on the other checkerboard and then shifted together. at the very end...
00286       //
00287       //  CB      1-CB          
00288       //    ^       |   
00289       //    |       |     
00290       //    |       V
00291       //    <-------X CB
00292       
00293       
00294       // 3) Mu links
00295       //
00296       //  Compunte with low_left_corner:     ^           |
00297       //                                     |           | 
00298       //               low_left_corner    =  |           | 
00299       //                                     |           V
00300       //                              (1-CB) <--------   X CB
00301       u_tmp3[rb[1-cb]] = adj(u_nu_for_mu)*Lambda_xplus_mu;
00302       //
00303       // accumulate into ds_tmp_mu and shift at the end.
00304       ds_tmp_mu[rb[1-cb]] = u_tmp3*low_left_corner;
00305       
00306       // Nu links
00307       // 
00308       //  CB    ------>                                     ------->
00309       //                |                                          |
00310       //                |      reuse adj(up_right_corner):         |
00311       //                |                                          |
00312       //                V                                          V
00313       //  1-CB   <------X
00314       u_tmp3[rb[1-cb]] = adj(up_right_corner)*Lambda_xplus_mu;
00315       ds_u_nu[rb[1-cb]] = u_tmp3*adj(u[mu]);
00316       
00317       
00318       
00319       // 4) Mu links
00320       //
00321       //  1-CB      CB
00322       //   ^        |
00323       //   |        |        reuse = u[nu](x+mu) = u_nu_for_mu
00324       //   |        |
00325       //   X <----- V 1-CB
00326       //   CB
00327       u_tmp3[rb[cb]] = low_right_corner*Lambda;
00328       //
00329       // accumulate into ds_tmp_mu and shift at the end.
00330       ds_tmp_mu[rb[cb]] = u_tmp3*u[nu];
00331       
00332       
00333       
00334       // Nu links
00335       // 
00336       //  1-CB   ------> X                               
00337       //               |                                          |
00338       //               |       reuse low_right_corner:            |
00339       //               |                                          |
00340       //               V                                          V
00341       //   CB   <------                                    <------
00342       u_tmp3[rb[cb]] =    u_mu_for_nu*Lambda_xplus_muplusnu;
00343       ds_u_nu[rb[cb]] =   u_tmp3*low_right_corner;
00344       
00345       
00346       //  ds_tmp_mu now holds the last 2 terms, one on each of its checkerboards, but Now I need
00347       //  to shift them both together onto ds_u_mu
00348       //  I'll keep them in ds_tmp_mu right, bearing in mind I'll need to bring
00349       //  them in with a -ve contribution...
00350       
00351 
00352       // STAPLE TERMS:   
00353       
00354       // Construct the staples
00355 
00356       //  Staple_for =  <--------
00357       //                |       ^
00358       //                |       |             ON ALL CHECKERBOARDS
00359       //                |       |             
00360       //                V       |
00361       staple_for = u_nu_for_mu*up_left_corner;
00362 
00363 
00364       // Staple_right =   <-----             ON ALL CHECKERBOARDS
00365       //                 |
00366       //                 |
00367       //                 V
00368       //                 ----->
00369       staple_right = up_left_corner*u[mu];
00370       
00371       
00372       
00373       //                 ----->
00374       //                       |
00375       //                       |
00376       //                       |
00377       //                <----- V
00378       staple_left  = u_mu_for_nu*low_right_corner;
00379       
00380       
00381       
00382       
00383       //  Staple_back =  ^       |
00384       //                 |       |            ON ALL CHECKERBOARDS
00385       //                 |       |
00386       //                 <------ V
00387       //                      
00388       staple_back = adj(u_nu_for_mu)*low_left_corner;
00389       
00390     }  // Corner pieces go away here
00391     
00392     // 5) Mu links
00393     //
00394     //    <------- 
00395     //    |        ^
00396     //    |        |     use computed staple
00397     //    V        |
00398     //    x        
00399     //   CB       1-CB  
00400     ds_u_mu[rb[cb]] += staple_for*Lambda;
00401 
00402 
00403     //  Nu links
00404     //
00405     //     CB   <---- 1-CB
00406     //        |
00407     //        |                use staple_right
00408     //        V
00409     //    1-CB  -----> X CB
00410     //
00411     //  Accumulate into ds_tmp_nu and shift at the end.
00412 
00413     ds_tmp_nu[rb[1-cb]] += staple_right*Lambda_xplus_mu;
00414 
00415 
00416     // 6)  Mu links
00417     //
00418     //    <------- 
00419     //    |        ^
00420     //    |        |    re use computed staple 
00421     //    V        |
00422     //   1-CB      X CB   
00423 
00424     ds_u_mu[rb[1-cb]] += Lambda_xplus_mu*staple_for;
00425 
00426 
00427 
00428     //  Nu links
00429     // 
00430     //      <----  X CB
00431     //     |
00432     //     |                     use adj(staple_right)
00433     //     |
00434     // CB  V ----> (1-CB)
00435     ds_tmp_nu[rb[cb]] += Lambda_xplus_muplusnu * staple_right;
00436 
00437 
00438     // 7) Mu links
00439     //
00440     //   CB      1-CB
00441     //  X         
00442     //    ^       |
00443     //    |       |   re use computed staple 
00444     //    |       |
00445     //    <-------V 
00446     //
00447     //  Accumulate into ds_tmp_mu and shift at the end.
00448     ds_tmp_mu[rb[1-cb]] += staple_back*Lambda_xplus_nu;
00449 
00450     //   Now for nu
00451     //
00452     //   (1-CB)  -----> CB         use adj(staple_left)
00453     //                |
00454     //                |
00455     //                V
00456     //      CB X <----
00457     //
00458     ds_u_nu[rb[cb]] += staple_left*Lambda;
00459 
00460     // 8) Mu links
00461     //
00462     //  1-CB      X CB
00463     //    ^       |
00464     //    |       |  reuse computed staple 
00465     //    |       |
00466     //    <-------V
00467     //
00468     // Accumulate into ds_tmp_mu and shift at the end
00469     ds_tmp_mu[rb[cb]] += Lambda_xplus_muplusnu * staple_back;
00470 
00471     // Now for Nu
00472     // 
00473     //    CB X ------> (1-CB)
00474     //               |
00475     //               |
00476     //               |
00477     //               V
00478     // 1-CB  <------- CB
00479     ds_u_nu[rb[1-cb]] += Lambda_xplus_nu * staple_left;
00480 
00481     // Now shift the accumulated pieces to mu and nu
00482     // 
00483     // Hope that this is not too slow as an expression
00484     ds_u_mu -= shift(ds_tmp_mu, BACKWARD, nu);
00485     ds_u_nu -= shift(ds_tmp_nu, BACKWARD, mu); 
00486 
00487     END_CODE();
00488   }
00489 
00490 
00491   //! Take deriv of D
00492   /*!
00493    * \param chi     left vector on cb                           (Read)
00494    * \param psi     right vector on 1-cb                        (Read)
00495    * \param isign   D'^dag or D'  ( MINUS | PLUS ) resp.        (Read)
00496    * \param cb      Checkerboard of chi vector                  (Read)
00497    *
00498    * \return Computes   \f$\chi^\dag * \dot(D} * \psi\f$
00499    */
00500   template<typename T, typename U>
00501   void CloverTermBase<T,U>::deriv(multi1d<U>& ds_u, 
00502                              const T& chi, const T& psi, 
00503                              enum PlusMinus isign, int cb) const
00504   {
00505     START_CODE();
00506 
00507 
00508     // Do I still need to do this?
00509     if( ds_u.size() != Nd ) { 
00510       ds_u.resize(Nd);
00511     }
00512 
00513     ds_u = zero;
00514 
00515     // Get the links
00516     const multi1d<U>& u = getU();
00517 
00518 
00519     // Now compute the insertions
00520     for(int mu=0; mu < Nd; mu++) {
00521       for(int nu = mu+1; nu < Nd; nu++) {
00522         
00523         // These will be appropriately overwritten - no need to zero them.
00524         // Contributions to mu links from mu-nu clover piece
00525         U ds_tmp_mu; 
00526 
00527         // -ve contribs  to the nu_links from the mu-nu clover piece 
00528         // -ve because of the exchange of gamma_mu gamma_nu <-> gamma_nu gamma_mu
00529         U ds_tmp_nu;
00530 
00531         // The weight for the terms
00532         Real factor = (Real(-1)/Real(8))*getCloverCoeff(mu,nu);
00533 
00534         // Get gamma_mu gamma_nu psi -- no saving here, from storing shifts because
00535         // I now only do every mu, nu pair only once.
00536 
00537         int mu_nu_index = (1 << mu) + (1 << nu); // 2^{mu} 2^{nu}
00538         T ferm_tmp = Gamma(mu_nu_index)*psi;
00539         U s_xy_dag = traceSpin( outerProduct(ferm_tmp,chi));
00540         s_xy_dag *= Real(factor);
00541 
00542         // Compute contributions
00543         deriv_loops(mu, nu, cb, ds_tmp_mu, ds_tmp_nu, s_xy_dag);
00544 
00545         // Accumulate them
00546         ds_u[mu] += ds_tmp_mu;
00547         ds_u[nu] -= ds_tmp_nu;
00548 
00549 
00550       }
00551     }
00552 
00553 
00554     // Clear out the deriv on any fixed links
00555     (*this).getFermBC().zero(ds_u);
00556     END_CODE();
00557   }
00558 
00559 
00560   //! Take deriv of D using Trace Log
00561   /*!
00562    * \param chi     left vector on cb                           (Read)
00563    * \param psi     right vector on 1-cb                        (Read)
00564    * \param isign   D'^dag or D'  ( MINUS | PLUS ) resp.        (Read)
00565    * \param cb      Checkerboard of chi vector                  (Read)
00566    *
00567    * \return Computes   \f$\chi^\dag * \dot(D} * \psi\f$  
00568    */
00569   template<typename T, typename U>
00570   void CloverTermBase<T,U>::derivTrLn(multi1d<U>& ds_u, 
00571                                  enum PlusMinus isign, int cb) const
00572   {
00573     START_CODE();
00574     
00575     // Do I still need to do this?
00576     if( ds_u.size() != Nd ) { 
00577       ds_u.resize(Nd);
00578     }
00579     
00580     ds_u = zero;
00581 
00582     for(int mu=0; mu < Nd; mu++) {
00583       for(int nu = mu+1; nu < Nd; nu++) { 
00584 
00585           // Index 
00586           int mu_nu_index = (1 << mu) + (1 << nu); // 2^{mu} 2^{nu}
00587 
00588           // The actual coefficient factor
00589           Real factor = Real(-1)*getCloverCoeff(mu,nu)/Real(8);
00590           
00591           U sigma_XY_dag=zero;
00592 
00593           // Get  weight*Tr_spin gamma_mu gamma_nu A^{-1} piece
00594           triacntr(sigma_XY_dag, mu_nu_index, cb);
00595           sigma_XY_dag[rb[cb]] *= factor;
00596 
00597           // These will be overwritten so no need to initialize to zero
00598           U ds_tmp_mu;
00599           U ds_tmp_nu;
00600 
00601           // Get contributions from the loops and insersions
00602           deriv_loops(mu, nu, cb, ds_tmp_mu, ds_tmp_nu, sigma_XY_dag);
00603 
00604           // Accumulate
00605           ds_u[mu] += ds_tmp_mu;
00606           // -ve weight for nu from gamma_mu gamma_nu -> gamma_nu gamma_mu
00607           // commutation.
00608           ds_u[nu] -= ds_tmp_nu;
00609 
00610       } // End loop over nu
00611 
00612     } // end of loop over mu
00613     
00614 
00615     // Not sure this is needed here, but will be sure
00616     (*this).getFermBC().zero(ds_u);
00617     
00618     END_CODE();
00619   }
00620       
00621 
00622 
00623 } // End Namespace Chroma
00624 
00625 
00626 #endif

Generated on Sat Mar 13 04:29:06 2010 for CHROMA by  doxygen 1.4.7