invcg1.cc

Go to the documentation of this file.
00001 // $Id: invcg1.cc,v 3.5 2008/03/25 10:46:51 mcneile Exp $
00002 /*! \file
00003  *  \brief Conjugate-Gradient algorithm for a generic Linear Operator
00004  */
00005 
00006 #include "chromabase.h"
00007 #include "actions/ferm/invert/invcg1.h"
00008 
00009 using namespace QDP::Hints;
00010 
00011 namespace Chroma {
00012 
00013 //! Conjugate-Gradient (CGNE) algorithm for a generic Linear Operator
00014 /*! \ingroup invert
00015  * This subroutine uses the Conjugate Gradient (CG) algorithm to find
00016  * the solution of the set of linear equations
00017  *
00018  *          Chi  =  A . Psi
00019  *
00020  * where       A  is Hermitian Positive Definite
00021  *
00022  * Algorithm:
00023 
00024  *  Psi[0]  :=  initial guess;                 Linear interpolation (argument)
00025  *  r[0]    :=  Chi - A. Psi[0] ;              Initial residual
00026  *  p[1]    :=  r[0] ;                         Initial direction
00027  *  IF |r[0]| <= RsdCG |Chi| THEN RETURN;      Converged?
00028  *  FOR k FROM 1 TO MaxCG DO                   CG iterations
00029  *      a[k] := |r[k-1]|**2 / <p[k],Ap[k]> ;
00030  *      Psi[k] += a[k] p[k] ;                  New solution vector
00031  *      r[k] -= a[k] A. p[k] ;        New residual
00032  *      IF |r[k]| <= RsdCG |Chi| THEN RETURN;  Converged?
00033  *      b[k+1] := |r[k]|**2 / |r[k-1]|**2 ;
00034  *      p[k+1] := r[k] + b[k+1] p[k];          New direction
00035  *
00036  * Arguments:
00037  *
00038  *  \param M       Linear Operator             (Read)
00039  *  \param chi     Source                      (Read)
00040  *  \param psi     Solution                    (Modify)
00041  *  \param RsdCG   CG residual accuracy        (Rea/Write)
00042  *  \param MaxCG   Maximum CG iterations       (Read)
00043  *  \return res    System solver results
00044  *
00045  * Local Variables:
00046  *
00047  *  p                  Direction vector
00048  *  r                  Residual vector
00049  *  cp                 | r[k] |**2
00050  *  c                  | r[k-1] |**2
00051  *  k                  CG iteration counter
00052  *  a                  a[k]
00053  *  b                  b[k+1]
00054  *  d                  < p[k], A.p[k] >
00055  *  ap                 Temporary for  A.p
00056  *
00057  * Subroutines:
00058  *                             +               
00059  *  A       Apply matrix M or M  to vector
00060  *
00061  * Operations:
00062  *
00063  *  2 A + 2 Nc Ns + N_Count ( 2 A + 10 Nc Ns )
00064  */
00065 
00066 
00067 
00068 template<typename T>
00069 SystemSolverResults_t 
00070 InvCG1_a(const LinearOperator<T>& A,
00071          const T& chi,
00072          T& psi,
00073          const Real& RsdCG, 
00074          int MaxCG, int MinCG=0)
00075 {
00076   START_CODE();
00077 
00078   const Subset& s = A.subset();
00079 
00080   SystemSolverResults_t  res;
00081 
00082   T p;                 moveToFastMemoryHint(p);
00083   T ap;                moveToFastMemoryHint(ap);
00084   
00085   // Hint for psi to be moved with copy
00086   moveToFastMemoryHint(psi,true);
00087 
00088   T r;                 moveToFastMemoryHint(r);
00089   T chi_internal;      moveToFastMemoryHint(chi_internal);
00090 
00091   // Can't move chi to fast space, because its const.
00092   chi_internal[s]=chi;
00093 
00094   Real rsd_sq = (RsdCG * RsdCG) * Real(norm2(chi_internal,s));
00095 
00096   //
00097   //  r[0]  :=  Chi - A . Psi[0] 
00098     
00099   //                    
00100   //  r  :=  [ Chi  -  A . psi ]
00101 
00102 
00103   // A is Hermitian
00104   A(ap, psi, PLUS);
00105 
00106 
00107   r[s] = chi_internal - ap;
00108 
00109   //  p[1]  :=  r[0]
00110   p[s] = r;
00111   
00112   //  Cp = |r[0]|^2
00113   Double cp = norm2(r, s);                 /* 2 Nc Ns  flops */
00114 
00115 #if 0
00116   QDPIO::cout << "InvCG1: k = 0  cp = " << cp << "  rsd_sq = " << rsd_sq 
00117 << endl;
00118 #endif
00119 
00120   //  IF |r[0]| <= RsdCG |Chi| THEN RETURN;
00121   if ( toBool(cp  <=  rsd_sq) )
00122   {
00123     res.n_count = 0;
00124     res.resid   = sqrt(cp);
00125     revertFromFastMemoryHint(psi, true); // Revert psi, and copy contents
00126     END_CODE();
00127     return res;
00128   }
00129 
00130   //
00131   //  FOR k FROM 1 TO MaxCG DO
00132   //
00133   Real b;
00134   Double c;
00135   Complex a;
00136   Real d;
00137 
00138   for(int k = 1; k <= MaxCG; ++k)
00139   {
00140     //  c  =  | r[k-1] |**2
00141     c = cp;
00142 
00143     //  a[k] := | r[k-1] |**2 / < p[k], Ap[k] > ;
00144     //                                            +
00145     //  First compute  d  =  < p, A.p > 
00146    
00147 
00148     // SCRAP THIS IDEA FOR NOW AND DO <p, A.p> TO KEEP TRACK OF 
00149     // "PRECONDITIONING" So ap =MdagMp
00150 
00151     A(ap, p, PLUS);
00152     
00153     // d = <p,A.p>
00154     d = innerProductReal(p, ap, s);
00155 
00156     //    a = Real(c);
00157     a = Real(c)/d;
00158 
00159 
00160     //  Psi[k] += a[k] p[k]
00161     psi[s] += a * p;    /* 2 Nc Ns  flops */
00162 
00163     //  r[k] -= a[k] A . p[k] ;
00164     //                
00165     //  r  =  r  - a A p  
00166 
00167     r[s] -= a * ap;
00168 
00169 
00170 
00171     //  IF |r[k]| <= RsdCG |Chi| THEN RETURN;
00172 
00173     //  cp  =  | r[k] |**2
00174     cp = norm2(r, s);                   /* 2 Nc Ns  flops */
00175 
00176 #if 0
00177     QDPIO::cout << "InvCG1: k = " << k << "  cp = " << cp << endl;
00178 #endif
00179 
00180     if ( toBool(cp  <=  rsd_sq) && (toBool(MinCG <= 0 ) || toBool( k >= MinCG  )))
00181     {
00182       res.n_count = k;
00183       res.resid   = sqrt(cp);
00184       
00185       // Compute the actual residual
00186       {
00187         A(ap, psi, PLUS);
00188         Double actual_res = norm2(chi - ap,s);
00189         res.resid = sqrt(actual_res);
00190 #if 0
00191     QDPIO::cout << "InvCG1:  true residual:  " << res.resid << endl;
00192 #endif
00193       }
00194       revertFromFastMemoryHint(psi,true); // Get back psi, copy contents.
00195       END_CODE();
00196       return res;
00197     }
00198 
00199     //  b[k+1] := |r[k]|**2 / |r[k-1]|**2
00200     b = Real(cp) / Real(c);
00201 
00202     //  p[k+1] := r[k] + b[k+1] p[k]
00203     p[s] = r + b*p;     /* Nc Ns  flops */
00204   }
00205   res.n_count = MaxCG;
00206   res.resid   = sqrt(cp);
00207   QDP_error_exit("too many CG iterations: count = %d", res.n_count);
00208   revertFromFastMemoryHint(psi,true);
00209   END_CODE();
00210   return res;
00211 }
00212 
00213 // Fix here for now
00214 template<>
00215 SystemSolverResults_t 
00216 InvCG1(const LinearOperator<LatticeFermion>& A,
00217        const LatticeFermion& chi,
00218        LatticeFermion& psi,
00219        const Real& RsdCG, 
00220        int MaxCG,int MinCG)
00221 {
00222   return InvCG1_a(A, chi, psi, RsdCG, MaxCG,MinCG);
00223 }
00224 
00225 template<>
00226 SystemSolverResults_t 
00227 InvCG1(const LinearOperator<LatticeStaggeredFermion>& A,
00228        const LatticeStaggeredFermion& chi,
00229        LatticeStaggeredFermion& psi,
00230        const Real& RsdCG, 
00231        int MaxCG,int MinCG)
00232 {
00233   return InvCG1_a(A, chi, psi, RsdCG, MaxCG,MinCG);
00234 }
00235 
00236 }  // end namespace Chroma

Generated on Sun Mar 14 04:33:26 2010 for CHROMA by  doxygen 1.4.7