HArD::Core2D
Hybrid Arbitrary Degree::Core 2D - Library to implement 2D schemes with edge and cell polynomials as unknowns
linearsolver.hpp
Go to the documentation of this file.
1 // Class to select and apply solver
2 //
3 //
4 // Author: Jerome Droniou (jerome.droniou@monash.edu)
5 
6 
7 #ifndef LINEARSOLVER_HPP
8 #define LINEARSOLVER_HPP
9 
10 #include <Eigen/Dense>
11 #include <Eigen/Sparse>
12 
13 #ifdef WITH_UMFPACK
14 #include <Eigen/UmfPackSupport>
15 #endif
16 
17 #ifdef WITH_MKL
18 #include <Eigen/PardisoSupport>
19 #include <mkl.h>
20 #endif
21 
22 #ifdef WITH_PASTIX
23 #include <PastixInterface.hpp>
24 #endif
25 
26 #include <boost/algorithm/string.hpp>
27 
28 namespace HArDCore2D
29 {
37 
39  std::map<std::string, int> ParamName{
40  #ifdef WITH_PASTIX
41  {"eps_refinement",0},{"eps_ctrl",1}
42  #endif
43  };
44 
46  std::vector<double> SolverParam{
47  #ifdef WITH_PASTIX
48  -1.0, -1.0 // eps_refinement, eps_ctrl with default values
49  #endif
50  };
51 
53  const char *SolverParamHelper{
54  #ifdef WITH_PASTIX
55  "Set the solver parameters; Usage [with v1, v2 as doubles]: \n"
56  "--solver-parameters param1=v1 param2=v2\n"
57  "--solver-parameters param1=v1 --solver-parameters param2=v2 \n"
58  "-sparm param=v \n"
59  "Possible parameters are [all optionals]:\n eps_refinement \n eps_ctrl\n"
60  #else
61  "Set the solver parameters, not implemented with this solver, see src/Common/linearsolver.hpp for modifications\n"
62  #endif
63  };
64 
65  // Types of Eigen wrappers for each solver (if the module is not available, we define bools just to have a name of that type)
66  template<typename MatrixType>
67  using EigenLUType = Eigen::SparseLU<MatrixType>;
68  template<typename MatrixType>
69  using EigenBiCGStabType = Eigen::BiCGSTAB<MatrixType, Eigen::IncompleteLUT<double> >;
70 
71  template<typename MatrixType>
72  #ifdef WITH_MKL
73  using PardisoLUType = Eigen::PardisoLU<MatrixType>;
74  #else
75  using PardisoLUType = bool;
76  #endif
77 
78  template<typename MatrixType>
79  #ifdef WITH_UMFPACK
80  using UMFPACKType = Eigen::UmfPackLU<MatrixType>;
81  #else
82  using UMFPACKType = bool;
83  #endif
84 
85  #ifdef WITH_PASTIX
88  #else
89  using PastixLUType = bool;
90  using PastixLLTType = bool;
91  #endif
92 
93 
95 
96  std::map<std::string, SolverName> map_solver = {{"eigenlu",EigenLU},
97  {"eigenbicgstab",EigenBiCGStab},
98  {"pardisolu",PardisoLU},
99  {"umfpack",UMFPACK},
100  {"pastixlu",PaStiXLU},
101  {"pastixllt",PaStiXLLT},};
102 
104  std::map<SolverName, std::string> map_realname = {{EigenLU,"Eigen LU"},
105  {EigenBiCGStab,"Eigen BiCGStab"},
106  {PardisoLU,"Pardiso LU"},
107  {UMFPACK,"UMFPACK"},
108  {PaStiXLU,"PaStiX LU"},
109  {PaStiXLLT,"PaStiX LLT"}};
110 
111  std::map<SolverName, size_t> map_id = {{EigenLU,0},
112  {EigenBiCGStab,1},
113  {PardisoLU,2},
114  {UMFPACK,3},
115  {PaStiXLU,4},
116  {PaStiXLLT,5}};
117 
118 
119  // A tuple of unique pointers to list all available pointers (or "int" as a placeholder in case a pointer is not available),
120  // in the order in which they appear in SolverName. If "name" is a SolverName, a get<name> accesses the pointer corresponding to that solver.
121  template<typename MatrixType>
122  using ListSolvers = std::tuple<std::unique_ptr<EigenLUType<MatrixType>>,
123  std::unique_ptr<EigenBiCGStabType<MatrixType>>,
124  std::unique_ptr<PardisoLUType<MatrixType>>,
125  std::unique_ptr<UMFPACKType<MatrixType>>,
126  std::unique_ptr<PastixLUType>,
127  std::unique_ptr<PastixLLTType>>;
128 
129 
131  template<typename MatrixType>
133  {
134  public:
136 
138  LinearSolver(const std::string & namesolver)
139  : m_name(map_solver[boost::algorithm::to_lower_copy(namesolver)])
140  {
141  // We adjust the solver if the selected one was not available
142  #ifndef WITH_MKL
143  if (m_name == PardisoLU){
144  m_name = EigenLU;
145  std::cout << "[linearsolver] Pardiso not available, reverting to Eigen LU" << std::endl;
146  };
147  #endif
148  #ifndef WITH_UMFPACK
149  if (m_name == UMFPACK){
150  m_name = EigenLU;
151  std::cout << "[linearsolver] UMFPACK not available, reverting to Eigen LU" << std::endl;
152  };
153  #endif
154  #ifndef WITH_PASTIX
155  if (m_name == PaStiXLU || m_name == PaStiXLLT){
156  m_name = EigenLU;
157  std::cout << "[linearsolver] PaStiX not available, reverting to Eigen LU" << std::endl;
158  };
159  #endif
160 
161  // Instantiate selected solver, put all other pointers to NULL
162  switch(m_name){
163  case EigenLU:
164  {
165  std::get<0>(m_list_solvers).reset( new EigenLUType<MatrixType> );
166  break;
167  }
168  case EigenBiCGStab:
169  {
170  std::get<1>(m_list_solvers).reset( new EigenBiCGStabType<MatrixType> );
171  break;
172  }
173  #ifdef WITH_MKL
174  case PardisoLU:
175  {
176  unsigned nb_threads_hint = std::thread::hardware_concurrency();
177  mkl_set_dynamic(0);
178  mkl_set_num_threads(nb_threads_hint);
179  std::get<2>(m_list_solvers).reset( new PardisoLUType<MatrixType> );
180  break;
181  }
182  #endif
183  #ifdef WITH_UMFPACK
184  case UMFPACK:
185  {
186  std::get<3>(m_list_solvers).reset( new UMFPACKType<MatrixType>);
187  break;
188  }
189  #endif
190  #ifdef WITH_PASTIX
191  case PaStiXLU:
192  {
193  std::get<4>(m_list_solvers).reset( new PastixLUType );
194  std::get<4>(m_list_solvers).get()->init(SolverParam[0],SolverParam[1]);
195  break;
196  }
197  case PaStiXLLT:
198  {
199  std::get<5>(m_list_solvers).reset( new PastixLLTType );
200  break;
201  }
202  #endif
203  default:
204  break;
205  } // end switch
206  }; // end constructor
207 
209  std::string name() const
210  {
211  return map_realname[m_name];
212  }
213 
215  Eigen::ComputationInfo info_factorize() const
216  {
217  return m_info_factorize;
218  }
219 
221  Eigen::ComputationInfo info_solve() const
222  {
223  return m_info_solve;
224  }
225 
227  void analyzePattern(MatrixType & A
228  )
229  {
230  switch(m_name){
231  case EigenLU:
232  {
233  std::get<0>(m_list_solvers).get()->analyzePattern(A);
234  break;
235  }
236  case EigenBiCGStab:
237  {
238  std::get<1>(m_list_solvers).get()->analyzePattern(A);
239  break;
240  }
241  #ifdef WITH_MKL
242  case PardisoLU:
243  {
244  std::get<2>(m_list_solvers).get()->analyzePattern(A);
245  break;
246  }
247  #endif
248 
249  #ifdef WITH_UMFPACK
250  case UMFPACK:
251  {
252  std::get<3>(m_list_solvers).get()->analyzePattern(A);
253  break;
254  }
255  #endif
256 
257  #ifdef WITH_PASTIX
258  case PaStiXLU:
259  {
260  std::get<4>(m_list_solvers).get()->analyzePattern(A);
261  break;
262  }
263 
264  case PaStiXLLT:
265  {
266  std::get<5>(m_list_solvers).get()->analyzePattern(A);
267  break;
268  }
269  #endif
270 
271  default:
272  break;
273  } // end switch for m_name
274 
275  }
276 
278  void factorize(MatrixType & A
279  )
280  {
281  switch(m_name){
282  case EigenLU:
283  {
284  std::get<0>(m_list_solvers).get()->factorize(A);
285  m_info_factorize = std::get<0>(m_list_solvers).get()->info();
286  break;
287  }
288  case EigenBiCGStab:
289  {
290  std::get<1>(m_list_solvers).get()->factorize(A);
291  m_info_factorize = std::get<1>(m_list_solvers).get()->info();
292  break;
293  }
294  #ifdef WITH_MKL
295  case PardisoLU:
296  {
297  std::get<2>(m_list_solvers).get()->factorize(A);
298  m_info_factorize = std::get<2>(m_list_solvers).get()->info();
299  break;
300  }
301  #endif
302 
303  #ifdef WITH_UMFPACK
304  case UMFPACK:
305  {
306  std::get<3>(m_list_solvers).get()->factorize(A);
307  m_info_factorize = std::get<3>(m_list_solvers).get()->info();
308  break;
309  }
310  #endif
311 
312  #ifdef WITH_PASTIX
313  case PaStiXLU:
314  {
315  std::get<4>(m_list_solvers).get()->factorize(A);
316  m_info_factorize = std::get<4>(m_list_solvers).get()->info();
317  break;
318  }
319 
320  case PaStiXLLT:
321  {
322  std::get<5>(m_list_solvers).get()->factorize(A);
323  m_info_factorize = std::get<5>(m_list_solvers).get()->info();
324  break;
325  }
326  #endif
327 
328  default:
329  break;
330  } // end switch for m_name
331 
332  _check_info(m_info_factorize, "factorize");
333 
334  }
335 
337  void compute(MatrixType & A
338  )
339  {
340  analyzePattern(A);
341  factorize(A);
342  }
343 
345  template<typename VectorType>
346  VectorType solve(VectorType & b
347  )
348  {
349  VectorType x;
350 
351  switch(m_name){
352  case EigenLU:
353  {
354  x = std::get<0>(m_list_solvers).get()->solve(b);
355  m_info_solve = std::get<0>(m_list_solvers).get()->info();
356  break;
357  }
358  case EigenBiCGStab:
359  {
360  x = std::get<1>(m_list_solvers).get()->solve(b);
361  m_info_solve = std::get<1>(m_list_solvers).get()->info();
362  break;
363  }
364  #ifdef WITH_MKL
365  case PardisoLU:
366  {
367  x = std::get<2>(m_list_solvers).get()->solve(b);
368  m_info_solve = std::get<2>(m_list_solvers).get()->info();
369  break;
370  }
371  #endif
372 
373  #ifdef WITH_UMFPACK
374  case UMFPACK:
375  {
376  x = std::get<3>(m_list_solvers).get()->solve(b);
377  m_info_solve = std::get<3>(m_list_solvers).get()->info();
378  break;
379  }
380  #endif
381 
382  #ifdef WITH_PASTIX
383  case PaStiXLU:
384  {
385  x = std::get<4>(m_list_solvers).get()->solve(b);
386  m_info_solve = std::get<4>(m_list_solvers).get()->info();
387  break;
388  }
389 
390  case PaStiXLLT:
391  {
392  x = std::get<5>(m_list_solvers).get()->solve(b);
393  m_info_solve = std::get<5>(m_list_solvers).get()->info();
394  break;
395  }
396  #endif
397 
398  default:
399  break;
400  } // end switch for m_name
401 
402  _check_info(m_info_solve, "solve");
403 
404  return x;
405  };
406 
408  template<typename VectorType>
409  VectorType compute_and_solve(MatrixType & A,
410  VectorType & b
411  )
412  {
413  analyzePattern(A);
414  factorize(A);
415  return solve(b);
416  }
417 
419  template <typename VectorType>
420  inline double residual(MatrixType & A, VectorType & b, VectorType & x)
421  { return (A*x - b).template lpNorm<Eigen::Infinity>() / (b.template lpNorm<Eigen::Infinity>()+1e-8); };
422 
423  private:
424 
425  // Checks an info, and stop the execution if there is an error
426  void _check_info(Eigen::ComputationInfo const & info, std::string step) const
427  {
428  if (info != Eigen::Success) {
429  std::cerr << "[linearsolver] ERROR in step: " << step << std::endl;
430  std::cerr << "[linearsolver] Info: " << info << " (see Eigen::ComputationInfo for the meaning)" << std::endl;
431  exit(1);
432  }
433  }
434 
435  // Members
436  SolverName m_name;
437  ListSolvers<MatrixType> m_list_solvers;
438  Eigen::ComputationInfo m_info_factorize;
439  Eigen::ComputationInfo m_info_solve;
440  }; // end definition class
441 
442 
444 
445 } // end namespace HArDCore2D
446 
447 
448 #endif
Class to invoke the Pastix LLT solver.
Definition: PastixInterface.hpp:543
Class to invoke the Pastix LU solver.
Definition: PastixInterface.hpp:424
This structure is a wrapper to allow a given code to select various linear solvers.
Definition: linearsolver.hpp:133
bool PardisoLUType
Definition: linearsolver.hpp:75
VectorType compute_and_solve(MatrixType &A, VectorType &b)
Perform all operators to solve Ax=b.
Definition: linearsolver.hpp:409
SolverName
Enumeration of all available solvers.
Definition: linearsolver.hpp:36
const char * SolverParamHelper
Create a solver specific description in boost::desc.options.
Definition: linearsolver.hpp:53
LinearSolver(const std::string &namesolver)
Constructor.
Definition: linearsolver.hpp:138
std::map< std::string, SolverName > map_solver
Map to associate to each lowercase name a solver.
Definition: linearsolver.hpp:96
double residual(MatrixType &A, VectorType &b, VectorType &x)
Check relative infinity norm of residual: ||Ax-b||/||b||.
Definition: linearsolver.hpp:420
Eigen::ComputationInfo info_solve() const
Returns the information message after the "solve" step.
Definition: linearsolver.hpp:221
std::string name() const
Returns the name of the solver.
Definition: linearsolver.hpp:209
Eigen::ComputationInfo info_factorize() const
Returns the information message after the "factorize" step.
Definition: linearsolver.hpp:215
void analyzePattern(MatrixType &A)
Analyze the pattern of the matrix.
Definition: linearsolver.hpp:227
std::tuple< std::unique_ptr< EigenLUType< MatrixType > >, std::unique_ptr< EigenBiCGStabType< MatrixType > >, std::unique_ptr< PardisoLUType< MatrixType > >, std::unique_ptr< UMFPACKType< MatrixType > >, std::unique_ptr< PastixLUType >, std::unique_ptr< PastixLLTType > > ListSolvers
Definition: linearsolver.hpp:127
std::map< std::string, int > ParamName
To parse optional Solver parameter from command line.
Definition: linearsolver.hpp:39
std::vector< double > SolverParam
Create space and stores default values of optional solver parameters.
Definition: linearsolver.hpp:46
Eigen::BiCGSTAB< MatrixType, Eigen::IncompleteLUT< double > > EigenBiCGStabType
Definition: linearsolver.hpp:69
bool UMFPACKType
Definition: linearsolver.hpp:82
std::map< SolverName, std::string > map_realname
Map to associate to each solver its proper name.
Definition: linearsolver.hpp:104
Eigen::SparseLU< MatrixType > EigenLUType
Definition: linearsolver.hpp:67
void compute(MatrixType &A)
Analyze and factorize the matrix.
Definition: linearsolver.hpp:337
std::map< SolverName, size_t > map_id
Definition: linearsolver.hpp:111
bool PastixLUType
Definition: linearsolver.hpp:89
bool PastixLLTType
Definition: linearsolver.hpp:90
VectorType solve(VectorType &b)
Solve the system Ax=b using the selected solver (after analysis of pattern and computation of matrix)
Definition: linearsolver.hpp:346
void factorize(MatrixType &A)
Factorize the matrix.
Definition: linearsolver.hpp:278
@ PaStiXLU
Definition: linearsolver.hpp:36
@ UMFPACK
Definition: linearsolver.hpp:36
@ EigenLU
Definition: linearsolver.hpp:36
@ PaStiXLLT
Definition: linearsolver.hpp:36
@ PardisoLU
Definition: linearsolver.hpp:36
@ EigenBiCGStab
Definition: linearsolver.hpp:36
A
Definition: mmread.m:102
Definition: ddr-klplate.hpp:27