CHROMA
syssolver_mdagm_qop_mg_w.cc
Go to the documentation of this file.
1 /*! \file
2  * \brief Make contact with the QDP clover multigrid solver, transfer
3  * the gauge field, generate the coarse grids, solve systems
4  */
5 #include "state.h"
9 #include <cstdio>
10 #include <ostream>
11 
14 //Added support for MG predictor.
17 
18 #include "meas/glue/mesplq.h"
19 
20 #if BASE_PRECISION == 32
21 #define QDP_Precision 'F'
22 #define QLA_Precision 'F'
23 #define toReal toFloat
24 #elif BASE_PRECISION == 64
25 #define QDP_Precision 'D'
26 #define QLA_Precision 'D'
27 #define toReal toDouble
28 #endif
29 
30 extern "C" {
31  // This should be placed on the include path.
32 #include "wilsonmg-interface.h"
33 
34 }
35 
36 namespace Chroma
37 {
38 
39  namespace MGMdagMInternal {
40 
41  /*! This will remap the MdagM params for the linop. For example,
42  * we will turn off the TerminateOnFail feature, so that this outer solver
43  * can control termination
44  */
46  {
47  SysSolverQOPMGParams ret_val = invParam_;
48  ret_val.TerminateOnFail = false; // Turn off terminate on fail as we
49  // will retry from MdagM
50 
51  ret_val.MaxIter = invParam_.MaxIter/2; // MdagM is 2 solves, so I want a maxIter that is for 1 solve, which hopefully should be about 1/2 of MdagM
52  return ret_val;
53  }
54  };
55 
56  // This will come from syssolver_linop_qop_mg_w.h
57  // static multi1d<LatticeColorMatrix> u;
58  // These functions will allow QDP to look into the Chroma gauge field and set
59  // the QDP gauge field at each site equal to the one in Chroma. There doesn't
60  // seem to be a good way to treat the extra std::vector index of the gauge field,
61 
63  Handle< FermState<LatticeFermion,multi1d<LatticeColorMatrix>,multi1d<LatticeColorMatrix > > > state_,
64  const SysSolverQOPMGParams& invParam_) :
65  A(A_),
66  state(state_),
67  invParam(invParam_),
68  Dinv(new LinOpSysSolverQOPMG(A_,state_,MGMdagMInternal::remapParams(invParam_)))
69  {
70  QDPIO::cout<<"MdagM multigrid initialized"<<std::endl;
71  }
72 
74  {
75  //if (invParam.Levels<0) MGP(finalize)();
76  }
77 
78 
79  //! Solve the linear system
80  /*!
81  * \param psi solution ( Modify )
82  * \param chi source ( Read )
83  * \return syssolver results
84  */
86  MdagMSysSolverQOPMG::operator() (LatticeFermion& psi, const LatticeFermion& chi, AbsChronologicalPredictor4D<LatticeFermion>& predictor) const
87  {
88  START_CODE();
89  typedef LatticeFermion T;
90  typedef multi1d<LatticeColorMatrix> P;
91  typedef multi1d<LatticeColorMatrix> Q;
93 
94  try {
95  AbsTwoStepChronologicalPredictor4D<T>& two_step_predictor =
96  dynamic_cast<AbsTwoStepChronologicalPredictor4D<T>& >(predictor);
97 
98  // This is the unpreconditioned operator
99  // Whenever we call its op() it will underneath call unprecLinOp()
100  Lunprec<T,P,Q> A_unprec(A);
101 
102  SystemSolverResults_t individual_res;
103  StopWatch swatch;
104  swatch.reset();
105  swatch.start();
106 
107  // we will solve for g5 D g5 D psi = chi
108  // so psi = D^(-1)g5 D^(-1) g5 chi
109 
110  // Set up the source: g5 chi
111  T g5chi = zero;
112  g5chi[A->subset()] = Gamma(Nd*Nd-1)*chi ;
113  Double g5chi_norm = sqrt(norm2(g5chi, A->subset()));
114 
115  T tmpsol_tmp; // This will hold our temporary solution
116  T tmpferm=zero;
117 
118  // OK: predictY will predict the solution of M^\dagger Y = b
119  // which is the same as Y = g_5 (M^{-1}) g_5 b
120  // but actually we will really only want Y = (M^{-1}) g_5 b
121  // so after prediction, we have to hit the prediction result
122  // with gamma_5. TO AVOID ALLOCATING AN EXTRA FERMION
123  // I am using tmpsol_tmp as the source. I am not using chi itself
124  // in case for any reason it is dirty outside the target subset.
125  tmpsol_tmp = zero;
126  tmpsol_tmp[ A->subset() ] = chi;
127 
128  // predict with M^\dagger into tmpferm
129  two_step_predictor.predictY(tmpferm, A_unprec, tmpsol_tmp);
130 
131  // hit tmpferm with g_5 to get the initial guess
132  tmpsol_tmp = Gamma(Nd*Nd -1 )*tmpferm;
133  Double init_norm = norm2(tmpsol_tmp, all);
134  QDPIO::cout << "Initial guess norm_sq = " << init_norm << " norm = " << sqrt(init_norm) << std::endl;
135 
136  // Now do the solve
137  individual_res = (*Dinv)(tmpsol_tmp,g5chi);
138 
139 
140  T tmpsol = zero;
141  tmpsol[ A->subset() ] = tmpsol_tmp; // Do this in case tmpsol_tmp is dirtied up outside its target
142  res.n_count = individual_res.n_count;
143 
144  Double rel_resid = individual_res.resid / g5chi_norm;
145 
146  // If we've reached iteration-threshold, then destroy the subspace. The next solve will
147  // refresh it.
148  if ( individual_res.n_count >= invParam.RefreshThreshold ) {
149 
150  QDPIO::cout << "QOPMG_MDAGM_SOLVER: RefreshThreshold Iterations (" << invParam.RefreshThreshold <<")"
151  << " reached in first LinopSolver call."
152  << " Erasing subspace: " << invParam.SubspaceId << std::endl;
153 
154  // Erase the subspace from Dinv and if saved from the
155  // NamedObjectMap
156  (*Dinv).eraseSubspace();
157 
158  // Re solve if needed
159  if ( toBool( rel_resid > invParam.Residual ) ) {
160  QDPIO::cout << "QOPMG_MDAGM_SOLVER: First solve failed with RelResid = " << rel_resid
161  << " Re-trying with refreshed subspace " << std::endl;
162 
163  // tmpsol_tmp may already be a good guess...
164  individual_res = (*Dinv)(tmpsol_tmp,g5chi);
165  tmpsol=zero;
166  tmpsol[ A->subset() ] = tmpsol_tmp; // Do this in case tmpsol_tmp is dirtied up outside of its target subset
167  res.n_count += individual_res.n_count;
168 
169  rel_resid = individual_res.resid / g5chi_norm;
170  if ( toBool( rel_resid > invParam.Residual) ) {
171  QDPIO::cout << "QOP_MG_MDAGM_SOLVER: Re-solving of first solve with refreshed space failed with RelResid = " << rel_resid
172  <<" Giving Up! " << std::endl;
173  QDP_abort(1);
174  }
175  }
176  }
177 
178 
179  // At this point either
180  // -- the first solve worked.
181  // -- OR the first solve didn't converge, got refreshed, resolved and worked
182  // -- In either case, tmpsol, should be good and tmpsol_tmp holds the
183  // full solution on both subsets. Add it to the predictor.
184  two_step_predictor.newYVector(tmpsol_tmp);
185 
186 
187  T tmpsol2 = zero ;
188  tmpsol2[A->subset()] = Gamma(Nd*Nd-1)*tmpsol ;
189  Double tmpsol2_norm = sqrt(norm2(tmpsol2,A->subset()));
190 
191  // This is less elaborate. predict X will call with A_unprec
192  // no gamma_5 tricks needed
193  tmpsol_tmp = zero;
194  two_step_predictor.predictX(tmpsol_tmp, A_unprec, tmpsol2);
195 
196  init_norm = norm2(tmpsol_tmp, all);
197  QDPIO::cout << "Initial guess norm_sq = " << init_norm << " norm = " << sqrt(init_norm) << std::endl;
198 
199  individual_res = (*Dinv)(tmpsol_tmp,tmpsol2);
200 
201  psi = zero;
202  psi[ A->subset() ] = tmpsol_tmp; // Do this in case tmpsol tmp is dirty outside subset
203 
204  res.n_count += individual_res.n_count;
205  rel_resid = individual_res.resid / tmpsol2_norm;
206 
207  // If we've reached max iter, then destroy the subspace. The next solve will
208  if ( individual_res.n_count >= invParam.RefreshThreshold ) {
209 
210  QDPIO::cout << "QOPMG_MDAGM_SOLVER: RefreshThreshold Iterations (" << invParam.RefreshThreshold <<")"
211  << " reached in second LinopSolver call."
212  << " Erasing subspace: " << invParam.SubspaceId << std::endl;
213 
214  // Erase the subspace from Dinv and if saved from the
215  // NamedObjectMap
216  (*Dinv).eraseSubspace();
217 
218 
219  // Re solve if needed
220  if ( toBool( rel_resid > invParam.Residual ) ) {
221 
222  QDPIO::cout << "QOPMG_MDAGM_SOLVER: Second solve failed with RelResid = " << rel_resid
223  << " Re-trying with refreshed subspace " << std::endl;
224 
225  // tmpsol_tmp may already be a good initial guess
226  individual_res = (*Dinv)(tmpsol_tmp,tmpsol2); // This will internally refresh the subspace
227  psi=zero;
228  psi[ A->subset() ] = tmpsol_tmp; // Do this in case tmpsol_tmp is dirty outside subset
229  res.n_count += individual_res.n_count;
230 
231  rel_resid = individual_res.resid / tmpsol2_norm;
232  if ( toBool( rel_resid > invParam.Residual ) ) {
233  QDPIO::cout << "QOP_MG_MDAGM_SOLVER: Re-solving of second solve with refreshed space failed with RelResid = " << rel_resid
234  <<" Giving Up! " << std::endl;
235 
236  QDP_abort(1);
237  }
238  }
239  }
240 
241 
242 
243  // At this point either the second solve will have succeeded and was good
244  // OR the second solve will have failed, got subspace refreshed, and resolved if needed.
245 
246  // So add tmpsol_tmp to the chrono
247  two_step_predictor.newXVector(tmpsol_tmp);
248  swatch.stop();
249 
250  double time = swatch.getTimeInSeconds();
251  {
252  T r;
253  r[A->subset()] = chi;
254  T tmp;
255  T tmp2 ;
256  (*A)(tmp2, psi , PLUS );
257  (*A)(tmp , tmp2, MINUS);
258 
259  r[A->subset()] -= tmp;
260  res.resid = sqrt(norm2(r, A->subset()));
261  rel_resid = res.resid / sqrt(norm2(chi, A->subset()));
262  }
263 
264  QDPIO::cout << "QOPMG_MDAGM_SOLVER: "
265  << " Mass: " << invParam.Mass
266  << " iterations: " << res.n_count
267  << " time: " << time << " sec."
268  << " Rsd: " << res.resid
269  << " Relative Rsd: " << rel_resid
270  << std::endl;
271 
272  if ( toBool( rel_resid > invParam.RsdToleranceFactor*invParam.Residual ) ) {
273  if( invParam.TerminateOnFail ) {
274  QDPIO::cout << "***** !!! ERROR !!! NONCONVERGENCE !!! Mass="<<invParam.Mass <<" Aborting !!! *******" << std::endl;
275  QDP_abort(1);
276  }
277  else {
278  QDPIO::cout << "***** !!! WARNING!!! NONCONVERGENCE !!! Mass="<<invParam.Mass <<" !!! *******" << std::endl;
279  }
280  }
281  }
282  catch(std::bad_cast& bc) {
283  QDPIO::cout << "Couldnt cast predictor to two step predictor" << std::endl;
284  QDP_abort(1);
285  }
286 
287  END_CODE();
288  return res;
289  }
290 
291  //! Solve the linear system
292  /*!
293  * \param psi solution ( Modify )
294  * \param chi source ( Read )
295  * \param isign solve with dagger or not
296  * \return syssolver results
297  */
298  // T is the Lattice Fermion type
300  MdagMSysSolverQOPMG::operator() (LatticeFermion& psi, const LatticeFermion& chi) const
301  {
302  /* Ignoring the predictor for now, since I am solving the UNPREC system anyway as a gateway to solve the PREC system. The prec
303  solutions provided by the predictory are good for the PREC system, but may not be good enoug (missing half of) the solution
304  of the the UNPREC system */
305  Null4DChronoPredictor not_predicting;
306  SystemSolverResults_t res = (*this)(psi,chi, not_predicting);
307  return res;
308  }//! Solve the linear system
309 
310 
311  //! QDP multigrid system solver namespace
312  namespace MdagMSysSolverQOPMGEnv
313  {
314  //! Anonymous namespace
315  namespace
316  {
317  //! Name to be used
318  const std::string name("QOP_CLOVER_MULTIGRID_INVERTER");
319 
320  //! Local registration flag
321  bool registered = false;
322  }
323 
324 
325  //! Callback function for standard precision
327  createFerm( XMLReader& xml_in,
328  const std::string& path,
329  Handle< FermState< LatticeFermion,
330  multi1d<LatticeColorMatrix>,
331  multi1d<LatticeColorMatrix> > > state,
333  {
334  return new MdagMSysSolverQOPMG(A, state, SysSolverQOPMGParams(xml_in, path));
335  }
336 
337  /*MdagMSystemSolver<LatticeFermion>* createFerm(XMLReader& xml_in,
338  const std::string& path,
339  Handle< FermState< LatticeFermion, multi1d<LatticeColorMatrix>, multi1d<LatticeColorMatrix> > > state,
340 
341  Handle< LinearOperator<LatticeFermion> > A)
342  {
343  return new MdagMSysSolverQOPMG<LatticeFermion>(A, state, SysSolverQOPMGParams(xml_in, path));
344  }*/
345 
346  /*//! Callback function for single precision
347  MdagMSystemSolver<LatticeFermionF>*
348  createFermF( XMLReader& xml_in,
349  const std::string& path,
350  Handle< FermState< LatticeFermionF,
351  multi1d<LatticeColorMatrixF>,
352  multi1d<LatticeColorMatrixF> > > state,
353  Handle< LinearOperator<LatticeFermionF> > A)
354  {
355  return new MdagMSysSolverQOPMG<LatticeFermionF>
356  (A, SysSolverQOPMGParams(xml_in, path));
357  }*/
358 
359  //! Register all the factories
360  bool registerAll()
361  {
362  bool success = true;
363  if (! registered)
364  {
366  //success &= Chroma::TheMdagMFFermSystemSolverFactory::Instance().registerObject(name, createFermF);
367  registered = true;
368  }
369  return success;
370  }
371  }
372 }
Abstract interface for a Chronological Solution predictor.
virtual void predictY(T &Y, const T &chi, const Subset &s) const
virtual void newYVector(const T &Y)=0
virtual void predictX(T &X, const T &chi, const Subset &s) const
virtual void newXVector(const T &X)=0
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 using the external QDP multigrid inverter.
Gamma(5) hermitian linear operator.
Definition: lunprec_w.h:22
Solve a M*psi=chi linear system using the external QDP multigrid inverter.
multi1d< LatticeColorMatrix > Q
SystemSolverResults_t operator()(T &psi, const T &chi) const
Solver the linear system.
~MdagMSysSolverQOPMG()
Destructor finalizes the QDP environment.
Handle< LinearOperator< T > > A
Zero initial guess predictor.
static T & Instance()
Definition: singleton.h:432
multi1d< int > bc
Nd
Definition: meslate.cc:74
Double tmp2
Definition: mesq.cc:30
Named object function std::map.
static bool registered
Local registration flag.
const std::string name
Name to be used.
multi1d< LatticeColorMatrix > P
SysSolverQOPMGParams remapParams(const SysSolverQOPMGParams &invParam_)
bool registerAll()
Register all the factories.
MdagMSystemSolver< LatticeFermion > * createFerm(XMLReader &xml_in, const std::string &path, Handle< FermState< LatticeFermion, multi1d< LatticeColorMatrix >, multi1d< LatticeColorMatrix > > > state, Handle< LinearOperator< LatticeFermion > > A)
Callback function for standard precision.
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
LatticeFermion tmp
Definition: mespbg5p_w.cc:36
@ 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
FloatingPoint< double > Double
Definition: gtest.h:7351
::std::string string
Definition: gtest.h:1979
Null predictor: Leaves input x0 unchanged.
Support class for fermion actions and linear operators.
Parameters for the external QDP multigrid inverter.
Holds return info from SystemSolver call.
Definition: syssolver.h:17
Make contact with the QDP clover multigrid solver, transfer the gauge field, generate the coarse grid...
Register MdagM system solvers.
Factory for producing system solvers for MdagM*psi = chi.
Make contact with the QDP clover multigrid solver, transfer the gauge field, generate the coarse grid...