QUDA  1.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
solver.cpp
Go to the documentation of this file.
1 #include <quda_internal.h>
2 #include <invert_quda.h>
3 #include <multigrid.h>
4 #include <eigensolve_quda.h>
5 #include <cmath>
6 
7 namespace quda {
8 
9  static void report(const char *type) {
10  if (getVerbosity() >= QUDA_VERBOSE) printfQuda("Creating a %s solver\n", type);
11  }
12 
14  param(param),
15  profile(profile),
16  node_parity(0),
17  eig_solve(nullptr)
18  {
19  // compute parity of the node
20  for (int i=0; i<4; i++) node_parity += commCoords(i);
22  }
23 
25  {
26  if (eig_solve) {
27  delete eig_solve;
28  eig_solve = nullptr;
29  }
30  }
31 
32  // solver factory
34  DiracMatrix &matPrecon, TimeProfile &profile)
35  {
36  Solver *solver = nullptr;
37 
38  if (param.preconditioner && param.inv_type != QUDA_GCR_INVERTER)
39  errorQuda("Explicit preconditoner not supported for %d solver", param.inv_type);
40 
42  errorQuda("Explicit preconditoner not supported for %d preconditioner", param.inv_type_precondition);
43 
44  switch (param.inv_type) {
45  case QUDA_CG_INVERTER:
46  report("CG");
47  solver = new CG(mat, matSloppy, param, profile);
48  break;
50  report("BiCGstab");
51  solver = new BiCGstab(mat, matSloppy, matPrecon, param, profile);
52  break;
53  case QUDA_GCR_INVERTER:
54  report("GCR");
55  if (param.preconditioner) {
56  Solver *mg = param.mg_instance ? static_cast<MG*>(param.preconditioner) : static_cast<multigrid_solver*>(param.preconditioner)->mg;
57  // FIXME dirty hack to ensure that preconditioner precision set in interface isn't used in the outer GCR-MG solver
58  if (!param.mg_instance) param.precision_precondition = param.precision_sloppy;
59  solver = new GCR(mat, *(mg), matSloppy, matPrecon, param, profile);
60  } else {
61  solver = new GCR(mat, matSloppy, matPrecon, param, profile);
62  }
63  break;
65  report("CA-CG");
66  solver = new CACG(mat, matSloppy, param, profile);
67  break;
69  report("CA-CGNE");
70  solver = new CACGNE(mat, matSloppy, param, profile);
71  break;
73  report("CA-CGNR");
74  solver = new CACGNR(mat, matSloppy, param, profile);
75  break;
77  report("CA-GCR");
78  solver = new CAGCR(mat, matSloppy, param, profile);
79  break;
80  case QUDA_MR_INVERTER:
81  report("MR");
82  solver = new MR(mat, matSloppy, param, profile);
83  break;
84  case QUDA_SD_INVERTER:
85  report("SD");
86  solver = new SD(mat, param, profile);
87  break;
88  case QUDA_XSD_INVERTER:
89 #ifdef MULTI_GPU
90  report("XSD");
91  solver = new XSD(mat, param, profile);
92 #else
93  errorQuda("Extended Steepest Descent is multi-gpu only");
94 #endif
95  break;
96  case QUDA_PCG_INVERTER:
97  report("PCG");
98  solver = new PreconCG(mat, matSloppy, matPrecon, param, profile);
99  break;
100  case QUDA_MPCG_INVERTER:
101  report("MPCG");
102  solver = new MPCG(mat, param, profile);
103  break;
105  report("MPBICGSTAB");
106  solver = new MPBiCGstab(mat, param, profile);
107  break;
109  report("BICGSTABL");
110  solver = new BiCGstabL(mat, matSloppy, param, profile);
111  break;
112  case QUDA_EIGCG_INVERTER:
113  report("EIGCG");
114  solver = new IncEigCG(mat, matSloppy, matPrecon, param, profile);
115  break;
117  report("INC EIGCG");
118  solver = new IncEigCG(mat, matSloppy, matPrecon, param, profile);
119  break;
121  report("GMRESDR");
122  if (param.preconditioner) {
123  multigrid_solver *mg = static_cast<multigrid_solver*>(param.preconditioner);
124  // FIXME dirty hack to ensure that preconditioner precision set in interface isn't used in the outer GCR-MG solver
126  solver = new GMResDR(mat, *(mg->mg), matSloppy, matPrecon, param, profile);
127  } else {
128  solver = new GMResDR(mat, matSloppy, matPrecon, param, profile);
129  }
130  break;
131  case QUDA_CGNE_INVERTER:
132  report("CGNE");
133  solver = new CGNE(mat, matSloppy, param, profile);
134  break;
135  case QUDA_CGNR_INVERTER:
136  report("CGNR");
137  solver = new CGNR(mat, matSloppy, param, profile);
138  break;
139  case QUDA_CG3_INVERTER:
140  report("CG3");
141  solver = new CG3(mat, matSloppy, param, profile);
142  break;
143  case QUDA_CG3NE_INVERTER:
144  report("CG3NE");
145  solver = new CG3NE(mat, matSloppy, param, profile);
146  break;
147  case QUDA_CG3NR_INVERTER:
148  report("CG3NR");
149  // CG3NR is included in CG3NE
150  solver = new CG3NE(mat, matSloppy, param, profile);
151  break;
152  default:
153  errorQuda("Invalid solver type %d", param.inv_type);
154  }
155 
156  return solver;
157  }
158 
160  {
161  if (deflate_init) return;
162 
163  // Deflation requested + first instance of solver
164  profile.TPSTOP(QUDA_PROFILE_INIT);
166  profile.TPSTART(QUDA_PROFILE_INIT);
167 
168  // Clone from an existing vector
170  csParam.create = QUDA_ZERO_FIELD_CREATE;
171  // This is the vector precision used by matResidual
173  param.evecs.resize(param.eig_param.nConv);
174  for (int i = 0; i < param.eig_param.nConv; i++) param.evecs[i] = ColorSpinorField::Create(csParam);
175 
176  // Construct vectors to hold deflated RHS
177  defl_tmp1.push_back(ColorSpinorField::Create(csParam));
178  defl_tmp2.push_back(ColorSpinorField::Create(csParam));
179 
180  param.evals.resize(param.eig_param.nConv);
181  for (int i = 0; i < param.eig_param.nConv; i++) param.evals[i] = 0.0;
182  profile.TPSTOP(QUDA_PROFILE_INIT);
183  (*eig_solve)(param.evecs, param.evals);
184  profile.TPSTART(QUDA_PROFILE_INIT);
185 
186  if (svd) {
187  // Resize deflation space and compute left SV of M
188  for (int i = param.eig_param.nConv; i < 2 * param.eig_param.nConv; i++)
189  param.evecs.push_back(ColorSpinorField::Create(csParam));
190 
191  // Populate latter half of the array with left SV
193  }
194 
195  deflate_init = true;
196  }
197 
199  for (int i = 0; i < param.num_src; i++) {
200  (*this)(out.Component(i), in.Component(i));
203  }
204  }
205 
206  double Solver::stopping(double tol, double b2, QudaResidualType residual_type) {
207 
208  double stop=0.0;
209  if ( (residual_type & QUDA_L2_ABSOLUTE_RESIDUAL) &&
210  (residual_type & QUDA_L2_RELATIVE_RESIDUAL) ) {
211  // use the most stringent stopping condition
212  double lowest = (b2 < 1.0) ? b2 : 1.0;
213  stop = lowest*tol*tol;
214  } else if (residual_type & QUDA_L2_ABSOLUTE_RESIDUAL) {
215  stop = tol*tol;
216  } else {
217  stop = b2*tol*tol;
218  }
219 
220  return stop;
221  }
222 
223  bool Solver::convergence(double r2, double hq2, double r2_tol, double hq_tol) {
224 
225  // check the heavy quark residual norm if necessary
226  if ( (param.residual_type & QUDA_HEAVY_QUARK_RESIDUAL) && (hq2 > hq_tol) )
227  return false;
228 
229  // check the L2 relative residual norm if necessary
231  (param.residual_type & QUDA_L2_ABSOLUTE_RESIDUAL)) && (r2 > r2_tol) )
232  return false;
233 
234  return true;
235  }
236 
237  bool Solver::convergenceHQ(double r2, double hq2, double r2_tol, double hq_tol) {
238 
239  // check the heavy quark residual norm if necessary
240  if ( (param.residual_type & QUDA_HEAVY_QUARK_RESIDUAL) && (hq2 > hq_tol) )
241  return false;
242 
243  return true;
244  }
245 
246  bool Solver::convergenceL2(double r2, double hq2, double r2_tol, double hq_tol) {
247 
248  // check the L2 relative residual norm if necessary
250  (param.residual_type & QUDA_L2_ABSOLUTE_RESIDUAL)) && (r2 > r2_tol) )
251  return false;
252 
253  return true;
254  }
255 
256  void Solver::PrintStats(const char* name, int k, double r2, double b2, double hq2) {
257  if (getVerbosity() >= QUDA_VERBOSE) {
259  printfQuda("%s: %d iterations, <r,r> = %e, |r|/|b| = %e, heavy-quark residual = %e\n",
260  name, k, r2, sqrt(r2/b2), hq2);
261  } else {
262  printfQuda("%s: %d iterations, <r,r> = %e, |r|/|b| = %e\n",
263  name, k, r2, sqrt(r2/b2));
264  }
265  }
266 
267  if (std::isnan(r2)) errorQuda("Solver appears to have diverged");
268  }
269 
270  void Solver::PrintSummary(const char *name, int k, double r2, double b2,
271  double r2_tol, double hq_tol) {
272  if (getVerbosity() >= QUDA_SUMMARIZE) {
273  if (param.compute_true_res) {
275  printfQuda("%s: Convergence at %d iterations, L2 relative residual: iterated = %e, true = %e "
276  "(requested = %e), heavy-quark residual = %e (requested = %e)\n",
277  name, k, sqrt(r2/b2), param.true_res, sqrt(r2_tol/b2), param.true_res_hq, hq_tol);
278  } else {
279  printfQuda("%s: Convergence at %d iterations, L2 relative residual: iterated = %e, true = %e (requested = %e)\n",
280  name, k, sqrt(r2/b2), param.true_res, sqrt(r2_tol/b2));
281  }
282  } else {
284  printfQuda("%s: Convergence at %d iterations, L2 relative residual: iterated = %e "
285  "(requested = %e), heavy-quark residual = %e (requested = %e)\n",
286  name, k, sqrt(r2/b2), sqrt(r2_tol/b2), param.true_res_hq, hq_tol);
287  } else {
288  printfQuda("%s: Convergence at %d iterations, L2 relative residual: iterated = %e (requested = %e)\n",
289  name, k, sqrt(r2/b2), sqrt(r2_tol/b2));
290  }
291  }
292  }
293  }
294 
295  bool MultiShiftSolver::convergence(const double *r2, const double *r2_tol, int n) const {
296 
297  for (int i=0; i<n; i++) {
298  // check the L2 relative residual norm if necessary
300  (param.residual_type & QUDA_L2_ABSOLUTE_RESIDUAL)) && (r2[i] > r2_tol[i]) && r2_tol[i] != 0.0)
301  return false;
302  }
303 
304  return true;
305  }
306 
307 } // namespace quda
bool mg_instance
whether to use a global or local (node) reduction for this solver
Definition: invert_quda.h:248
Communication-avoiding CG solver. This solver does un-preconditioned CG, running in steps of nKrylov...
Definition: invert_quda.h:891
void setPrecision(QudaPrecision precision, QudaPrecision ghost_precision=QUDA_INVALID_PRECISION, bool force_native=false)
bool convergenceHQ(double r2, double hq2, double r2_tol, double hq_tol)
Test for HQ solver convergence – ignore L2 residual.
Definition: solver.cpp:237
enum QudaResidualType_s QudaResidualType
QudaInverterType inv_type
Definition: invert_quda.h:22
QudaVerbosity getVerbosity()
Definition: util_quda.cpp:21
#define errorQuda(...)
Definition: util_quda.h:121
__host__ __device__ ValueType sqrt(ValueType x)
Definition: complex_quda.h:120
int commCoords(int)
void PrintStats(const char *name, int k, double r2, double b2, double hq2)
Prints out the running statistics of the solver (requires a verbosity of QUDA_VERBOSE) ...
Definition: solver.cpp:256
Communication-avoiding GCR solver. This solver does un-preconditioned GCR, first building up a polyno...
Definition: invert_quda.h:990
static ColorSpinorField * Create(const ColorSpinorParam &param)
bool convergence(double r2, double hq2, double r2_tol, double hq_tol)
Definition: solver.cpp:223
TimeProfile & profile
Definition: invert_quda.h:464
ColorSpinorField & Component(const int idx) const
virtual ~Solver()
Definition: solver.cpp:24
QudaInverterType inv_type_precondition
Definition: invert_quda.h:28
std::vector< ColorSpinorField * > defl_tmp1
Definition: invert_quda.h:547
QudaGaugeParam param
Definition: pack_test.cpp:17
int nConv
Definition: quda.h:420
bool convergenceL2(double r2, double hq2, double r2_tol, double hq_tol)
Test for L2 solver convergence – ignore HQ residual.
Definition: solver.cpp:246
std::vector< ColorSpinorField * > defl_tmp2
Definition: invert_quda.h:548
bool convergence(const double *r2, const double *r2_tol, int n) const
Definition: solver.cpp:295
double tol
Definition: test_util.cpp:1656
static EigenSolver * create(QudaEigParam *eig_param, const DiracMatrix &mat, TimeProfile &profile)
Creates the eigensolver using the parameters given and the matrix.
QudaResidualType residual_type
Definition: invert_quda.h:49
double true_res_hq_offset[QUDA_MAX_MULTI_SHIFT]
Definition: invert_quda.h:187
static double stopping(double tol, double b2, QudaResidualType residual_type)
Set the solver L2 stopping condition.
Definition: solver.cpp:206
ColorSpinorParam csParam
Definition: pack_test.cpp:24
cpuColorSpinorField * in
static Solver * create(SolverParam &param, DiracMatrix &mat, DiracMatrix &matSloppy, DiracMatrix &matPrecon, TimeProfile &profile)
Definition: solver.cpp:33
virtual void blocksolve(ColorSpinorField &out, ColorSpinorField &in)
Definition: solver.cpp:198
void constructDeflationSpace(const ColorSpinorField &meta, const DiracMatrix &mat, bool svd)
Constructs the deflation space.
Definition: solver.cpp:159
void computeSVD(const DiracMatrix &mat, std::vector< ColorSpinorField *> &evecs, std::vector< Complex > &evals)
Computes Left/Right SVD from pre computed Right/Left.
double true_res_offset[QUDA_MAX_MULTI_SHIFT]
Definition: invert_quda.h:181
EigenSolver * eig_solve
Definition: invert_quda.h:545
std::vector< Complex > evals
Definition: invert_quda.h:61
QudaEigParam eig_param
Definition: invert_quda.h:55
QudaPrecision precision_precondition
Definition: invert_quda.h:151
std::vector< ColorSpinorField * > evecs
Definition: invert_quda.h:58
Solver(SolverParam &param, TimeProfile &profile)
Definition: solver.cpp:13
SolverParam & param
Definition: invert_quda.h:463
cpuColorSpinorField * out
static void report(const char *type)
Definition: solver.cpp:9
Conjugate-Gradient Solver.
Definition: invert_quda.h:570
void * preconditioner
Definition: invert_quda.h:33
#define printfQuda(...)
Definition: util_quda.h:115
QudaPrecision precision_sloppy
Definition: invert_quda.h:145
void PrintSummary(const char *name, int k, double r2, double b2, double r2_tol, double hq_tol)
Prints out the summary of the solver convergence (requires a verbosity of QUDA_SUMMARIZE). Assumes SolverParam.true_res and SolverParam.true_res_hq has been set.
Definition: solver.cpp:270
void mat(void *out, void **link, void *in, int dagger_bit, int mu, QudaPrecision sPrecision, QudaPrecision gPrecision)
bool deflate_init
Definition: invert_quda.h:546