CHROMA
syssolver_linop_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 
12 using namespace std;
13 
14 #if BASE_PRECISION == 32
15 #define QDP_Precision 'F'
16 #define QLA_Precision 'F'
17 #define toReal toFloat
18 #elif BASE_PRECISION == 64
19 #define QDP_Precision 'D'
20 #define QLA_Precision 'D'
21 #define toReal toDouble
22 #endif
23 
25 
26 extern "C" {
27  // This should be placed on the include path.
28 #include "wilsonmg-interface.h"
29 extern struct MGP(Clover_Params) PC(g_param);
30 }
31 
32 #include "meas/glue/mesplq.h"
33 
34 namespace Chroma
35 {
36 
37 
38 
39  static multi1d<LatticeColorMatrix> u;
40 // These functions will allow QDP to look into the Chroma gauge field and set
41 // the QDP gauge field at each site equal to the one in Chroma. There doesn't
42 // seem to be a good way to treat the extra std::vector index of the gauge field,
43 // so we make a std::vector of functions to carry that index.
44 #define index(c) c[0]+nrow[0]/2*(c[1]+nrow[1]*(c[2]+nrow[2]*(c[3]+nrow[3]*((c[0]+c[1]+c[2]+c[3])%2)))) // Hrm, this didn't seem to work; using linearSiteIndex for now...
45 #define pepo(d) \
46  void peekpoke##d(QLA(ColorMatrix) *dest, int coords[]) {\
47  START_CODE();\
48  multi1d<int> x(4); for (int i=0; i<4; i++) x[i] = coords[i];\
49  ColorMatrix U; U.elem() = u[d].elem(Layout::linearSiteIndex(x));\
50  END_CODE();\
51  \
52  QLA(Complex) z;\
53  QLA(Real) real, imag;\
54  for (int c1=0; c1<3; c1++)\
55  for (int c2=0; c2<3; c2++) {\
56  real = U.elem().elem().elem(c1,c2).real();\
57  imag = U.elem().elem().elem(c1,c2).imag();\
58  if (0&&c1==0&&c2==0) {std::fflush(stdout);printf("Chroma: gauge[%d] I am node %d, parsing %d %d %d %d; I see %g + I %g\n",d,Layout::nodeNumber(),x[0],x[1],x[2],x[3],real,imag); std::fflush(stdout);}\
59  QLA(C_eq_R_plus_i_R)(&z, &real, &imag);\
60  QLA_elem_M(*dest,c1,c2) = z;\
61  }\
62  }
63  pepo(0)
64  pepo(1)
65  pepo(2)
66  pepo(3)
67 #undef pepo
68 #undef index
69 
70  LinOpSysSolverQOPMG::
71  LinOpSysSolverQOPMG(Handle< LinearOperator<T> > A_,
72  Handle< FermState<T,Q,Q> > state_,
73  const SysSolverQOPMGParams& invParam_) :
74  A(A_), state(state_), invParam(invParam_), subspace(0x0)
75  {
76  // Copy the parameters read from XML into the QDP global structure
77  for (int d=0; d<4; d++) PC(g_param).bc[d] = 1;
78  PC(g_param).aniso_xi = toReal(invParam.AnisoXi);
79  PC(g_param).aniso_nu = toReal(invParam.AnisoNu);
80  PC(g_param).kappa = toReal(invParam.Kappa);
81  PC(g_param).kappac = toReal(invParam.KappaCrit);
82  PC(g_param).mass = toReal(invParam.Mass);
83  PC(g_param).massc = toReal(invParam.MassCrit);
84  PC(g_param).clov_s = toReal(invParam.Clover);
85  PC(g_param).clov_t = toReal(invParam.CloverT);
86  PC(g_param).res = toReal(invParam.Residual);
87  PC(g_param).ngcr = invParam.NumGCRVecs;
88  PC(g_param).maxiter = invParam.MaxIter;
89  PC(g_param).verb = invParam.Verbose;
90  PC(g_param).levels = invParam.Levels;
91 
92  for (int n=0; n<invParam.Levels; n++) {
93  for (int d=0; d<4; d++)
94  PC(g_param).block[n][d] = invParam.Blocking[n][d];
95  PC(g_param).nNullVecs[n] = invParam.NumNullVecs[n];
96  PC(g_param).nullMaxIter[n] = invParam.NullMaxIter[n];
97  PC(g_param).nullRes[n] = toReal(invParam.NullResidual[n]);
98  PC(g_param).nullConv[n] = toReal(invParam.NullConvergence[n]);
99  PC(g_param).nExtraVecs[n] = invParam.NumExtraVecs[n];
100  PC(g_param).urelax[n] = toReal(invParam.Underrelax[n]);
101  PC(g_param).npre[n] = invParam.NumPreHits[n];
102  PC(g_param).npost[n] = invParam.NumPostHits[n];
103  PC(g_param).cngcr[n] = invParam.CoarseNumGCRVecs[n];
104  PC(g_param).cmaxiter[n] = invParam.CoarseMaxIter[n];
105  PC(g_param).cres[n] = toReal(invParam.CoarseResidual[n]);
106  }
107 
108 // The std::vector of functions will be used by QDP to assign the gauge links
109 // at each site of the QDP lattice
110  if (invParam.Levels>0) {
111  /* We're going to pull the gauge field out of Chroma's aether */
112 #if 0
113  u = TheNamedObjMap::Instance().getData< multi1d<LatticeColorMatrix> >(invParam.GaugeID);
114 #else
115  u = state_->getLinks();
116 #endif
117  // Compute the plaquette for comparison with MG code
118  {
120 
122  QDPIO::cout << "Plaquette from State: " << std::endl;
123  QDPIO::cout << " w_plaq = " << w_plaq << std::endl;
124  QDPIO::cout << " s_plaq = " << s_plaq << std::endl;
125  QDPIO::cout << " t_plaq = " << t_plaq << std::endl;
126  QDPIO::cout << " link trace = " << link << std::endl;
127  }
128 
129  int machsize[4], latsize[4];
130  for (int d=0;d<4;d++) machsize[d] = Layout::logicalSize()[d];
131  for (int d=0;d<4;d++) latsize[d] = Layout::lattSize()[d];
132  void (*peekpoke[4])(QLA(ColorMatrix) *dest, int coords[]) =
133  {peekpoke0,peekpoke1,peekpoke2,peekpoke3};
134  MGP(initialize)(machsize, latsize, peekpoke);
135 
136  //MGP(teststuff)();
137  }
138  }
139 
140  LinOpSysSolverQOPMG::
141  ~LinOpSysSolverQOPMG()
142  {
143  // If we don't use an Externa subspace we should free it here.
144  if ( !invParam.ExternalSubspace ) {
145  if ( subspace != 0x0 ) MGP(destroy_subspace)(subspace);
146  }
147  MGP(finalize)();
148  }
149 
150 
152 
153  template<typename T>
154  void importFermion(QLA(DiracFermion) *dest, T* vec_src, int coords[])
155  {
156  multi1d<int> x(4); for (int i=0; i<4; i++) x[i] = coords[i];
157  Fermion src; src.elem() = ((T*)vec_src)->elem(Layout::linearSiteIndex(x));
158 
159  /*START_CODE();
160  double bsq = norm2(*(T*)fermionsrc).elem().elem().elem().elem();
161  printf("Chroma: in norm2 = %g\n",bsq);
162  END_CODE();*/
163  //printf("Chroma: x = %i %i %i %i:\n",x[0],x[1],x[2],x[3]);
164  QLA(Complex) z;
165  QLA(Real) real, imag;
166  for (int s=0; s<4; s++)
167  for (int c=0; c<3; c++) {
168  real = src.elem().elem(s).elem(c).real();
169  imag = src.elem().elem(s).elem(c).imag();
170  //printf("Chroma: s=%i,c=%i == %g + I %g\n",s,c,real,imag);
171  QLA(C_eq_R_plus_i_R)(&z, &real, &imag);
172  QLA(elem_D)(*dest,c,s) = z;
173  }
174  }
175 
176  template<typename T>
177  void peekpokesrc(QLA(DiracFermion) *dest, int coords[])
178  {
179  importFermion(dest, (T *)fermionsrc, coords);
180  }
181 
182  template<typename T>
183  void peekpokeguess(QLA(DiracFermion) *dest, int coords[])
184  {
185  importFermion(dest, (T *)fermionsol, coords);
186  }
187 
188 #if 0
189  template<typename T>
190  void peekpokesrc(QLA(DiracFermion) *dest, int coords[])
191  {
192  multi1d<int> x(4); for (int i=0; i<4; i++) x[i] = coords[i];
193  Fermion src; src.elem() = ((T*)fermionsrc)->elem(Layout::linearSiteIndex(x));
194  /*START_CODE();
195  double bsq = norm2(*(T*)fermionsrc).elem().elem().elem().elem();
196  printf("Chroma: in norm2 = %g\n",bsq);
197  END_CODE();*/
198  //printf("Chroma: x = %i %i %i %i:\n",x[0],x[1],x[2],x[3]);
199  QLA(Complex) z;
200  QLA(Real) real, imag;
201  for (int s=0; s<4; s++)
202  for (int c=0; c<3; c++) {
203  real = src.elem().elem(s).elem(c).real();
204  imag = src.elem().elem(s).elem(c).imag();
205  //printf("Chroma: s=%i,c=%i == %g + I %g\n",s,c,real,imag);
206  QLA(C_eq_R_plus_i_R)(&z, &real, &imag);
207  QLA(elem_D)(*dest,c,s) = z;
208  }
209  }
210 #endif
211 
212  template<typename T>
213  void peekpokesol(QLA(DiracFermion) *src, int coords[])
214  {
215  multi1d<int> x(4); for (int i=0; i<4; i++) x[i] = coords[i];
216  ColorVector ctmp;
217  Fermion ftmp;
218  /*START_CODE();
219  double bsq = norm2(*(T*)fermionsrc).elem().elem().elem().elem();
220  printf("Chroma: in norm2 = %g\n",bsq);
221  END_CODE();*/
222  //printf("Chroma: x = %i %i %i %i:\n",x[0],x[1],x[2],x[3]);
223  QLA(Complex) z;
224  QLA(Real) real, imag;
225  for (int s=0; s<4; s++) {
226  for (int c=0; c<3; c++) {
227  z = QLA_elem_D(*src,c,s);
228  QLA(R_eq_re_C)(&real, &z);
229  QLA(R_eq_im_C)(&imag, &z);
230  Complex ztmp = cmplx(Real(real), Real(imag));
231  pokeColor(ctmp, ztmp, c);
232  }
233  pokeSpin(ftmp, ctmp, s);
234  }
235  pokeSite(*((T*)fermionsol), ftmp, x);
236  }
237 
238  //! Solve the linear system
239  /*!
240  * \param psi solution ( Modify )
241  * \param chi source ( Read )
242  * \return syssolver results
243  */
244  SystemSolverResults_t
246  {
247  START_CODE();
248 
250 
251  StopWatch swatch;
252  swatch.reset();
253  swatch.start();
254 
255  int machsize[4], latsize[4];
256  for (int d=0;d<4;d++) machsize[d] = Layout::logicalSize()[d];
257  for (int d=0;d<4;d++) latsize[d] = Layout::lattSize()[d];
258 
259  // This will get the subspace
260  // If the subspace is externally managed it will be loaded/created
261  // If the subspace is internally managed it will be used/created
262  WilsonMGSubspace* solve_subspace = getSubspace();
263 
264 
265  // Set global pointers to our source and solution fermion fields
266  fermionsrc = (void*)&chi;
267  fermionsol = (void*)&psi;
268 
269  Double bsq = norm2(chi,all);
270  QDPIO::cout << "Chroma: chi all norm2 = " << bsq << std::endl;
271 
272  // DOING SOLVE HERE
273  res.n_count = MGP(solve)(peekpokesrc<T>, peekpokeguess<T>, peekpokesol<T>,solve_subspace);
274 
275  bsq = norm2(psi,all);
276  QDPIO::cout << "Chroma: psi all norm2 = " << bsq << std::endl;
277  swatch.stop();
278  Double rel_resid;
279  double time = swatch.getTimeInSeconds();
280  {
281  T r;
282  r[A->subset()] = chi;
283  T tmp;
284  (*A)(tmp, psi, PLUS);
285  r[A->subset()] -= tmp;
286  res.resid = sqrt(norm2(r, A->subset()));
287  rel_resid = res.resid / sqrt(norm2(chi, A->subset()));
288  }
289 
290  QDPIO::cout << "QOPMG_LINOP_SOLVER: "
291  << " Mass: " << invParam.Mass
292  << " iterations: " << res.n_count
293  << " time: " << time << " secs"
294  << " Rsd: " << res.resid
295  << " Relative Rsd: " << rel_resid
296  << std::endl;
297 
298  if ( invParam.TerminateOnFail ) {
299  if ( toBool( rel_resid >= invParam.RsdToleranceFactor*invParam.Residual ) ) {
300  QDPIO::cout << "!!!!! QOPMG_LINOP_SOLVER: "
301  << "Mass: " << invParam.Mass
302  << " did NOT CONVERGE: Target RelRsd = " << invParam.Residual
303  << " Actual RelRsd = " << rel_resid << std::endl;
304  QDPIO::cout << "Exiting !!!!! " << std::endl;
305  QDP_abort(1);
306  }
307  }
308 
309 
310  END_CODE();
311  return res;
312  }
313 
314  LinOpSysSolverQOPMG::WilsonMGSubspace* LinOpSysSolverQOPMG::getSubspace() const
315  {
316  WilsonMGSubspace *ret_val=0x0;
317  int machsize[4], latsize[4];
318  for (int d=0;d<4;d++) machsize[d] = Layout::logicalSize()[d];
319  for (int d=0;d<4;d++) latsize[d] = Layout::lattSize()[d];
320 
321  QDPIO::cout << "LinOpSysSolverQOPMG::getSubspace() " << std::endl;
322  if( !invParam.ExternalSubspace ) {
323  if( !subspace ) {
324  QDPIO::cout << "Internal doesn't yet exist... creating" << std::endl;
325  subspace = MGP(create_subspace)(latsize);
326  }
327  ret_val=subspace;
328  }
329  else {
330  // Check if ID exists in the map.
331  if( TheNamedObjMap::Instance().check(invParam.SubspaceId) ) {
332  QDPIO::cout << "Retreiving Subspace Pointer from NamedObject Map" << endl;
333  ret_val = TheNamedObjMap::Instance().getData< WilsonMGSubspace * >(invParam.SubspaceId);
334  MGP(reset_subspace)(latsize,ret_val);
335  }
336  else {
337  QDPIO::cout << "Using External Subspace but object ID: " << invParam.SubspaceId << " is not present in the NamedObject store." << std:: endl;
338  QDPIO::cout << "Creating a new one" << std::endl;
339  ret_val = MGP(create_subspace)(latsize);
340 
341  QDPIO::cout << "Saving in Map" << std::endl;
342  QDPIO::cout << "Creating Named Object Map Entry for subspace" << std::endl;
343  XMLBufferWriter file_xml;
344  push(file_xml, "FileXML");
345  pop(file_xml);
346 
347  XMLBufferWriter record_xml;
348  push(record_xml, "RecordXML");
349  write(record_xml, "InvertParam", invParam);
350  pop(record_xml);
351 
352  TheNamedObjMap::Instance().create< WilsonMGSubspace *>(invParam.SubspaceId);
353  TheNamedObjMap::Instance().get(invParam.SubspaceId).setFileXML(file_xml);
354  TheNamedObjMap::Instance().get(invParam.SubspaceId).setRecordXML(record_xml);
355  TheNamedObjMap::Instance().getData<WilsonMGSubspace*>(invParam.SubspaceId)=ret_val;
356  } // else of if Subspace ID is in the map
357  } // else of if !External Subspace
358 
359  return ret_val; // Return whichever pointer was the good one.
360  }
361 
362  void LinOpSysSolverQOPMG::eraseSubspace()
363  {
364  QDPIO::cout << "LinOpSysSolverQOPMG: Erasing Subspace" << endl;
365  if( !invParam.ExternalSubspace ) {
366 
367  QDPIO::cout << "My subspace does not come from the NamedObjMap" << std::endl;
368 
369  // Internal subspace case, if subspace is not null then free it.
370  if ( subspace != 0x0 ) {
371  QDPIO::cout << "My subspace pointer is not null... Destroying"
372  << std::endl;
373 
374  MGP(destroy_subspace)(subspace);
375  subspace = 0x0;
376  }
377  }
378  else {
379  // Using external subspace. If it exists free it.
380  if ( TheNamedObjMap::Instance().check(invParam.SubspaceId) ) {
381  QDPIO::cout << "MG Subspace: " << invParam.SubspaceId << " found. " << std::endl;
382 
383  // The loaded subspace ID is in the Map. Get it.
384  WilsonMGSubspace *named_obj_subspace = TheNamedObjMap::Instance().getData<WilsonMGSubspace*>(invParam.SubspaceId);
385  MGP(destroy_subspace)(named_obj_subspace);
386  try {
387  QDPIO::cout << "Attempting to delete from named object store" << std:: endl;
388  // Now erase the object
389  TheNamedObjMap::Instance().erase(invParam.SubspaceId);
390 
391  QDPIO::cout << "Object erased" << std::endl;
392  }
393  catch( std::bad_cast ) {
394  QDPIO::cerr <<" MGMdagMInternal::eraseSubspace: cast error"
395  << std::endl;
396  QDP_abort(1);
397  }
398  catch (const std::string& e) {
399 
400  QDPIO::cerr << " MGMdagMInternal::eraseSubspace: error message: " << e
401  << std::endl;
402  QDP_abort(1);
403  }
404 
405  QDPIO::cout << "Subspace: " << invParam.SubspaceId << " destroyed and removed from map" << std::endl;
406  }
407  else {
408  QDPIO::cout << "MG Subspace: " << invParam.SubspaceId << " is not in the map. Nothing to desroy" << std::endl;
409  }
410  }
411  }
412 
413  //! QDP multigrid system solver namespace
414  namespace LinOpSysSolverQOPMGEnv
415  {
416  //! Anonymous namespace
417  namespace
418  {
419  //! Name to be used
420  const std::string name("QOP_CLOVER_MULTIGRID_INVERTER");
421 
422  //! Local registration flag
423  bool registered = false;
424  }
425 
426 
427  //! Callback function for standard precision
429  createFerm( XMLReader& xml_in,
430  const std::string& path,
431  Handle< FermState< LatticeFermion,
432  multi1d<LatticeColorMatrix>,
433  multi1d<LatticeColorMatrix> > > state,
435  {
436  return new LinOpSysSolverQOPMG(A, state, SysSolverQOPMGParams(xml_in, path));
437  }
438 
439  /*//! Callback function for single precision
440  LinOpSystemSolver<LatticeFermionF>*
441  createFermF( XMLReader& xml_in,
442  const std::string& path,
443  Handle< FermState< LatticeFermionF,
444  multi1d<LatticeColorMatrixF>,
445  multi1d<LatticeColorMatrixF> > > state,
446  Handle< LinearOperator<LatticeFermionF> > A)
447  {
448  return new LinOpSysSolverQOPMG<LatticeFermionF>
449  (A, SysSolverQOPMGParams(xml_in, path));
450  }*/
451 
452  //! Register all the factories
453  bool registerAll()
454  {
455  bool success = true;
456  if (! registered)
457  {
459  //success &= Chroma::TheLinOpFFermSystemSolverFactory::Instance().registerObject(name, createFermF);
460  registered = true;
461  }
462  return success;
463  }
464  }
465 }
#define END_CODE()
Definition: chromabase.h:65
#define START_CODE()
Definition: chromabase.h:64
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.
Linear Operator.
Definition: linearop.h:27
static T & Instance()
Definition: singleton.h:432
void write(XMLWriter &xml, const std::string &path, const AsqtadFermActParams &param)
Writer parameters.
unsigned s
Definition: ldumul_w.cc:37
unsigned i
Definition: ldumul_w.cc:34
unsigned n
Definition: ldumul_w.cc:36
Double tmp
Definition: meslate.cc:60
int z
Definition: meslate.cc:36
int c
Definition: meslate.cc:61
int x
Definition: meslate.cc:34
Named object function std::map.
static bool registered
Local registration flag.
const std::string name
Name to be used.
multi1d< int > coords(const int x, const int y, const int z, const int t)
LinOpSystemSolver< 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.
bool registerAll()
Register all the factories.
MGSubspacePointers * create_subspace(const SysSolverQUDAMULTIGRIDCloverParams &invParam)
Definition: quda_mg_utils.h:37
multi1d< Hadron2PtContraction_t > operator()(const multi1d< LatticeColorMatrix > &u)
Asqtad Staggered-Dirac operator.
Definition: klein_gord.cc:10
static multi1d< LatticeColorMatrix > u
void peekpokesrc(QLA(DiracFermion) *dest, int coords[])
LinOpSysSolverMGProtoClover::T T
void peekpokeguess(QLA(DiracFermion) *dest, int coords[])
void initialize(int *argc, char ***argv)
Chroma initialisation routine.
Definition: chroma_init.cc:114
@ PLUS
Definition: chromabase.h:45
void finalize(void)
Chroma finalization routine.
Definition: chroma_init.cc:308
void peekpokesol(QLA(DiracFermion) *src, int coords[])
void MesPlq(const multi1d< LatticeColorMatrixF3 > &u, multi2d< Double > &plane_plaq, Double &link)
Definition: mesplq.cc:83
DComplex d
Definition: invbicg.cc:99
A(A, psi, r, Ncb, PLUS)
const WilsonTypeFermAct< multi1d< LatticeFermion > > Handle< const ConnectState > state
Definition: pbg5p_w.cc:28
void importFermion(QLA(DiracFermion) *dest, T *vec_src, int coords[])
Definition: gtest.h:745
FloatingPoint< double > Double
Definition: gtest.h:7351
::std::string string
Definition: gtest.h:1979
Double link
Definition: pade_trln_w.cc:146
multi1d< LatticeFermion > r(Ncb)
chi
Definition: pade_trln_w.cc:24
Double t_plaq
Definition: pade_trln_w.cc:145
psi
Definition: pade_trln_w.cc:191
Double w_plaq
Definition: pade_trln_w.cc:143
Double s_plaq
Definition: pade_trln_w.cc:144
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
Register linop system solvers that solve M*psi=chi.
Factory for solving M*psi=chi where M is not hermitian or pos. def.
#define pepo(d)
struct MGP(Clover_Params) PC(g_param)
Make contact with the QDP clover multigrid solver, transfer the gauge field, generate the coarse grid...
LatticeFermion T
Definition: t_clover.cc:11
push(xml_out,"Cooled_Topology")
pop(xml_out)