CHROMA
syssolver_linop_eigcg_array.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Solve a M*psi=chi linear system array by EigCG2
3  */
4 
5 #include <qdp-lapack.h>
6 
9 
13 
14 //for debugging
15 //#include "octave.h"
16 #define TEST_ALGORITHM
17 namespace Chroma
18 {
19 
20  //! CG1 system solver namespace
21  namespace LinOpSysSolverEigCGArrayEnv
22  {
23  //! Callback function
25  const std::string& path,
27  LatticeFermion,
28  multi1d<LatticeColorMatrix>,
29  multi1d<LatticeColorMatrix>
30  >
31  > state,
32 
34  {
36  }
37 
38  //! Name to be used
39  const std::string name("EIG_CG_INVERTER");
40 
41  //! Local registration flag
42  static bool registered = false;
43 
44  //! Register all the factories
45  bool registerAll()
46  {
47  bool success = true;
48  if (! registered)
49  {
51  registered = true;
52  }
53  return success;
54  }
55  }
56 
57 
58  //! Anonymous namespace holding method
59  namespace
60  {
61  //! Solver the linear system
62  /*!
63  * \param psi solution ( Modify )
64  * \param chi source ( Read )
65  * \return syssolver results
66  */
67  template<typename T>
68  SystemSolverResults_t sysSolver(multi1d<T>& psi, const multi1d<T>& chi,
69  const LinearOperatorArray<T>& A,
70  const LinearOperatorArray<T>& MdagM,
71  const SysSolverEigCGParams& invParam)
72  {
73  START_CODE();
74 #ifdef _WORKING_
75  multi1d<T> chi_tmp;
76  A(chi_tmp, chi, MINUS);
77 
78  int Ls = chi.size();
79 
80  LinAlg::RitzPairsArray<T>& GoodEvecs =
81  TheNamedObjMap::Instance().getData< LinAlg::RitzPairsArray<T> >(invParam.eigen_id);
82 
83  multi1d<Double> lambda; //the eigenvalues
84  multi2d<T> evec; // The eigenvectors
85  SystemSolverResults_t res; // initialized by a constructor
86  int n_CG(0);
87  // Need to pass the appropriate operators here...
88  InvEigCG2ArrayEnv::InitGuess(MdagM,psi,chi_tmp,GoodEvecs.eval.vec,GoodEvecs.evec.vec,GoodEvecs.Neig,n_CG);
89  if((GoodEvecs.Neig+invParam.Neig)<=invParam.Neig_max) // if there is space for new
90  {
91  StopWatch snoop;
92  snoop.reset();
93  snoop.start();
94 
95  evec.resize(0,0);// get in there with no evecs so that it computes new
96  res = InvEigCG2ArrayEnv::InvEigCG2(MdagM, psi, chi_tmp, lambda, evec,
97  invParam.Neig, invParam.Nmax,
98  invParam.RsdCG, invParam.MaxCG);
99  res.n_count += n_CG;
100 
101  snoop.start();
102  //GoodEvecs.evec.AddVectors(evec, MdagM.subset());
103  //GoodEvecs.eval.AddVectors(lambda,MdagM.subset());
104  GoodEvecs.AddVectors(lambda, evec, MdagM.subset());
105  snoop.stop();
106  double Time = snoop.getTimeInSeconds();
107  QDPIO::cout<<"GoodEvecs.Neig= "<<GoodEvecs.Neig<<std::endl;
108 
109  snoop.start();
110  normGramSchmidt(GoodEvecs.evec.vec,GoodEvecs.Neig-invParam.Neig,GoodEvecs.Neig,MdagM.subset());
111  normGramSchmidt(GoodEvecs.evec.vec,GoodEvecs.Neig-invParam.Neig,GoodEvecs.Neig,MdagM.subset());
112  snoop.stop();
113  Time += snoop.getTimeInSeconds();
114 
115  snoop.start();
116  LinAlg::Matrix<DComplex> Htmp(GoodEvecs.Neig);
117  InvEigCG2ArrayEnv::SubSpaceMatrix(Htmp,MdagM,GoodEvecs.evec.vec,GoodEvecs.Neig);
118  //Octave::PrintOut(Htmp.mat,Htmp.N,Octave::tag("H"),"RayleighRich.m");
119  char V = 'V'; char U = 'U';
120  QDPLapack::zheev(V,U,Htmp.mat,lambda);
121  evec.resize(GoodEvecs.Neig,Ls);
122  //Octave::PrintOut(Htmp.mat,Htmp.N,Octave::tag("Hevec"),"RayleighRich.m");
123  //evec.resize(GoodEvecs.Neig);
124  for(int k(0);k<GoodEvecs.Neig;k++){
125  GoodEvecs.eval[k] = lambda[k];
126  for(int s=0; s < Ls; ++s)
127  evec[k][s][MdagM.subset()] = zero;
128  for(int j(0);j<GoodEvecs.Neig;j++)
129  for(int s=0; s < Ls; ++s)
130  evec[k][s][MdagM.subset()] += conj(Htmp(k,j))*GoodEvecs.evec[j][s];
131  //QDPIO::cout<<"norm(evec["<<k<<"])=";
132  //QDPIO::cout<< sqrt(norm2(GoodEvecs.evec[k],MdagM.subset()))<<std::endl;
133  }
134  snoop.stop();
135  Time += snoop.getTimeInSeconds();
136  QDPIO::cout << "Evec_Refinement: time = "
137  << Time
138  << " secs" << std::endl;
139 
140  QDPIO::cout<<"GoodEvecs.Neig= "<<GoodEvecs.Neig<<std::endl;
141  for(int k(0);k<GoodEvecs.Neig;k++)
142  for(int s=0; s < Ls; ++s)
143  GoodEvecs.evec[k][s][MdagM.subset()] = evec[k][s];
144 
145  //Check the quality of eigenvectors
146 #ifdef TEST_ALGORITHM
147  {
148  multi1d<T> Av;
149  for(int k(0);k<GoodEvecs.Neig;k++)
150  {
151  MdagM(Av,GoodEvecs.evec[k],PLUS);
152  DComplex rq = innerProduct(GoodEvecs.evec[k],Av,MdagM.subset());
153  for(int s=0; s < Ls; ++s)
154  Av[s][MdagM.subset()] -= GoodEvecs.eval[k]*GoodEvecs.evec[k][s];
155  Double tt = sqrt(norm2(Av,MdagM.subset()));
156  QDPIO::cout<<"REFINE: error evec["<<k<<"] = "<<tt<<" ";
157  QDPIO::cout<<"--- eval ="<<GoodEvecs.eval[k]<<" ";
158  tt = sqrt(norm2(GoodEvecs.evec[k],MdagM.subset()));
159  QDPIO::cout<<"--- rq ="<<real(rq)<<" ";
160  QDPIO::cout<<"--- norm = "<<tt<<std::endl;
161  }
162  }
163 #endif
164  }// if there is space
165  else // call CG but ask it not to compute vectors
166  {
167  evec.resize(0,0);
168  n_CG = res.n_count;
169  if(invParam.vPrecCGvecs ==0){
171  psi,
172  chi_tmp,
173  lambda,
174  evec,
175  0, //Eigenvectors to keep
176  invParam.Nmax, // Max vectors to work with
177  invParam.RsdCGRestart[0], // CG residual.... Empirical restart need a param here...
178  invParam.MaxCG // Max CG itterations
179  );
180  }
181  else
182  res = InvEigCG2ArrayEnv::vecPrecondCG(MdagM,psi,chi_tmp,GoodEvecs.eval.vec,GoodEvecs.evec.vec,
183  invParam.vPrecCGvecStart,
184  invParam.vPrecCGvecStart+invParam.vPrecCGvecs,
185  invParam.RsdCG, // CG residual
186  invParam.MaxCG // Max CG itterations
187  );
188  res.n_count += n_CG;
189  n_CG=0;
190  QDPIO::cout<<"Restart1: "<<std::endl;
191  InvEigCG2ArrayEnv::InitGuess(MdagM,psi,chi_tmp,GoodEvecs.eval.vec,GoodEvecs.evec.vec,GoodEvecs.Neig, n_CG);
192  res.n_count += n_CG;
193  n_CG = res.n_count;
194  if(invParam.vPrecCGvecs ==0)
196  psi,
197  chi_tmp,
198  lambda,
199  evec,
200  0, //Eigenvectors to keep
201  invParam.Nmax, // Max vectors to work with
202  invParam.RsdCG, // CG residual....
203  invParam.MaxCG // Max CG itterations
204  );
205  else
206  res= InvEigCG2ArrayEnv::vecPrecondCG(MdagM,psi,chi_tmp,GoodEvecs.eval.vec,GoodEvecs.evec.vec,
207  invParam.vPrecCGvecStart,
208  invParam.vPrecCGvecStart+invParam.vPrecCGvecs,
209  invParam.RsdCG, // CG residual
210  invParam.MaxCG // Max CG itterations
211  );
212  res.n_count += n_CG;
213  }
214 #else
215  SystemSolverResults_t res; // initialized by a constructor
216  QDPIO::cerr<<" OOOPS! EigCG does not work with DWF\n";
217  exit(1);
218 #endif
219  END_CODE();
220 
221  return res;
222  }
223 
224  } // anonymous namespace
225 
226 
227  //
228  // Wrappers
229  //
230 
231  // LatticeFermionF
232  template<>
233  SystemSolverResults_t
234  LinOpSysSolverEigCGArray<LatticeFermionF>::operator()(multi1d<LatticeFermionF>& psi, const multi1d<LatticeFermionF>& chi) const
235  {
236  return sysSolver(psi, chi, *A, *MdagM, invParam);
237  }
238 
239  // LatticeFermionD
240  template<>
242  LinOpSysSolverEigCGArray<LatticeFermionD>::operator()(multi1d<LatticeFermionD>& psi, const multi1d<LatticeFermionD>& chi) const
243  {
244  return sysSolver(psi, chi, *A, *MdagM, invParam);
245  }
246 
247 
248 }
Support class for fermion actions and linear operators.
Definition: state.h:94
Class for counted reference semantics.
Definition: handle.h:33
Solve a M*psi=chi linear system by CG2 with eigenvectors.
SystemSolverResults_t operator()(multi1d< T > &psi, const multi1d< T > &chi) const
Solver the linear system.
Linear Operator to arrays.
Definition: linearop.h:61
static T & Instance()
Definition: singleton.h:432
void normGramSchmidt(multi1d< LatticeFermionF > &vec, int f, int t, const Subset &sub)
Gram-Schmidt with normalization.
Conjugate-Gradient algorithm with eigenstd::vector acceleration.
unsigned j
Definition: ldumul_w.cc:35
BinaryReturn< C1, C2, FnInnerProduct >::Type_t innerProduct(const QDPSubType< T1, C1 > &s1, const QDPType< T2, C2 > &s2)
SystemSolverResults_t InvEigCG2(const LinearOperatorArray< LatticeFermionF > &A, multi1d< LatticeFermionF > &x, const multi1d< LatticeFermionF > &b, multi1d< Double > &eval, multi2d< LatticeFermionF > &evec, int Neig, int Nmax, const Real &RsdCG, int MaxCG)
void SubSpaceMatrix(LinAlg::Matrix< DComplex > &H, const LinearOperatorArray< LatticeFermionF > &A, const multi2d< LatticeFermionF > &evec, int Nvecs)
SystemSolverResults_t vecPrecondCG(const LinearOperatorArray< LatticeFermionF > &A, multi1d< LatticeFermionF > &x, const multi1d< LatticeFermionF > &b, const multi1d< Double > &eval, const multi2d< LatticeFermionF > &evec, int startV, int endV, const Real &RsdCG, int MaxCG)
void InitGuess(const LinearOperatorArray< LatticeFermionF > &A, multi1d< LatticeFermionF > &x, const multi1d< LatticeFermionF > &b, const multi1d< Double > &eval, const multi2d< LatticeFermionF > &evec, int &n_count)
bool registerAll()
Register all the factories.
LinOpSystemSolverArray< LatticeFermion > * createFerm(XMLReader &xml_in, const std::string &path, Handle< FermState< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > > state, Handle< LinearOperatorArray< LatticeFermion > > A)
Callback function.
const std::string name("EIG_CG_INVERTER")
Name to be used.
static bool registered
Local registration flag.
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
@ MINUS
Definition: chromabase.h:45
@ PLUS
Definition: chromabase.h:45
multi1d< LatticeFermion > chi(Ncb)
LatticeFermion psi
Definition: mespbg5p_w.cc:35
START_CODE()
A(A, psi, r, Ncb, PLUS)
const WilsonTypeFermAct< multi1d< LatticeFermion > > Handle< const ConnectState > state
Definition: pbg5p_w.cc:28
Double zero
Definition: invbicg.cc:106
int k
Definition: invbicg.cc:119
multi1d< LatticeFermion > s(Ncb)
FloatingPoint< double > Double
Definition: gtest.h:7351
::std::string string
Definition: gtest.h:1979
Gram-Schmidt with normalization.
Params for EigCG inverter.
Holds return info from SystemSolver call.
Definition: syssolver.h:17
Register linop system solvers that solve M*psi=chi.
Solve a M*psi=chi linear system array by EigCG2.
Factory for solving M*psi=chi where M is not hermitian or pos. def.
Handle< LinearOperator< T > > MdagM
multi1d< LatticeColorMatrix > U