Amesos2 - Direct Sparse Solver Interfaces  Version of the Day
Amesos2_Details_LinearSolverFactory_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Amesos2: Templated Direct Sparse Solver Package
4 //
5 // Copyright 2011 NTESS and the Amesos2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
13 
14 #ifndef AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
15 #define AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
16 
17 #include "Amesos2_config.h"
18 #include "Amesos2_Factory.hpp"
19 #include "Amesos2_Solver.hpp"
20 #include "Trilinos_Details_LinearSolver.hpp"
21 #include "Trilinos_Details_LinearSolverFactory.hpp"
22 #include <type_traits>
23 
24 
25 #ifdef HAVE_AMESOS2_EPETRA
26 # include "Epetra_CrsMatrix.h"
27 #endif // HAVE_AMESOS2_EPETRA
28 
29 // mfh 23 Jul 2015: Tpetra is currently a required dependency of Amesos2.
30 #ifndef HAVE_AMESOS2_TPETRA
31 # define HAVE_AMESOS2_TPETRA
32 #endif // HAVE_AMESOS2_TPETRA
33 
34 #ifdef HAVE_AMESOS2_TPETRA
35 # include "Tpetra_CrsMatrix.hpp"
36 #endif // HAVE_AMESOS2_TPETRA
37 
38 namespace Amesos2 {
39 namespace Details {
40 
41 // For a given linear algebra implementation's Operator type OP,
42 // find the corresponding CrsMatrix type.
43 //
44 // Amesos2 unfortunately only does ETI for Tpetra::CrsMatrix, even
45 // though it could very well take Tpetra::RowMatrix.
46 template<class OP>
47 struct GetMatrixType {
48  typedef int type; // flag (see below)
49 
50 
51 #ifdef HAVE_AMESOS2_EPETRA
52  static_assert(! std::is_same<OP, Epetra_MultiVector>::value,
53  "Amesos2::Details::GetMatrixType: OP = Epetra_MultiVector. "
54  "This probably means that you mixed up MV and OP.");
55 #endif // HAVE_AMESOS2_EPETRA
56 
57 #ifdef HAVE_AMESOS2_TPETRA
58  static_assert(! std::is_same<OP, Tpetra::MultiVector<typename OP::scalar_type,
59  typename OP::local_ordinal_type, typename OP::global_ordinal_type,
60  typename OP::node_type> >::value,
61  "Amesos2::Details::GetMatrixType: OP = Tpetra::MultiVector. "
62  "This probably means that you mixed up MV and OP.");
63 #endif // HAVE_AMESOS2_TPETRA
64 };
65 
66 #ifdef HAVE_AMESOS2_EPETRA
67 template<>
68 struct GetMatrixType<Epetra_Operator> {
69  typedef Epetra_CrsMatrix type;
70 };
71 #endif // HAVE_AMESOS2_EPETRA
72 
73 
74 #ifdef HAVE_AMESOS2_TPETRA
75 template<class S, class LO, class GO, class NT>
76 struct GetMatrixType<Tpetra::Operator<S, LO, GO, NT> > {
77  typedef Tpetra::CrsMatrix<S, LO, GO, NT> type;
78 };
79 #endif // HAVE_AMESOS2_TPETRA
80 
81 template<class MV, class OP, class NormType>
82 class LinearSolver :
83  public Trilinos::Details::LinearSolver<MV, OP, NormType>,
84  virtual public Teuchos::Describable
85 {
86 
87 #ifdef HAVE_AMESOS2_EPETRA
88  static_assert(! std::is_same<OP, Epetra_MultiVector>::value,
89  "Amesos2::Details::LinearSolver: OP = Epetra_MultiVector. "
90  "This probably means that you mixed up MV and OP.");
91  static_assert(! std::is_same<MV, Epetra_Operator>::value,
92  "Amesos2::Details::LinearSolver: MV = Epetra_Operator. "
93  "This probably means that you mixed up MV and OP.");
94 #endif // HAVE_AMESOS2_EPETRA
95 
96 public:
103  typedef typename GetMatrixType<OP>::type crs_matrix_type;
104  static_assert(! std::is_same<crs_matrix_type, int>::value,
105  "Amesos2::Details::LinearSolver: The given OP type is not "
106  "supported.");
107 
109  typedef Amesos2::Solver<crs_matrix_type, MV> solver_type;
110 
124  LinearSolver (const std::string& solverName) :
125  solverName_ (solverName)
126  {
127  // FIXME (mfh 25 Aug 2015) Ifpack2::Details::Amesos2Wrapper made
128  // the unfortunate choice to attempt to guess solvers that exist.
129  // Thus, alas, for the sake of backwards compatibility, we must
130  // make an attempt to guess for the user. Furthermore, for strict
131  // backwards compatibility, we should preserve the same (rather
132  // arbitrary) list of choices, in the same order.
133  if (solverName == "") {
134  // KLU2 is the default solver.
135  if (Amesos2::query ("klu2")) {
136  solverName_ = "klu2";
137  }
138  else if (Amesos2::query ("superlu")) {
139  solverName_ = "superlu";
140  }
141  else if (Amesos2::query ("superludist")) {
142  solverName_ = "superludist";
143  }
144  else if (Amesos2::query ("cholmod")) {
145  solverName_ = "cholmod";
146  }
147  else if (Amesos2::query ("cusolver")) {
148  solverName_ = "cusolver";
149  }
150  else if (Amesos2::query ("basker")) {
151  solverName_ = "basker";
152  }
153  else if (Amesos2::query ("shylubasker")) {
154  solverName_ = "shylubasker";
155  }
156  else if (Amesos2::query ("ShyLUBasker")) {
157  solverName_ = "shylubasker";
158  }
159  else if (Amesos2::query ("superlumt")) {
160  solverName_ = "superlumt";
161  }
162  else if (Amesos2::query ("pardiso_mkl")) {
163  solverName_ = "pardiso_mkl";
164  }
165  else if (Amesos2::query ("css_mkl")) {
166  solverName_ = "css_mkl";
167  }
168  else if (Amesos2::query ("mumps")) {
169  solverName_ = "mumps";
170  }
171  else if (Amesos2::query ("lapack")) {
172  solverName_ = "lapack";
173  }
174  else if (Amesos2::query ("umfpack")) {
175  solverName_ = "umfpack";
176  }
177  // We don't have to try to rescue the user if their empty solver
178  // name didn't catch any of the above choices.
179  }
180  }
181 
183  virtual ~LinearSolver () {}
184 
189  void setMatrix (const Teuchos::RCP<const OP>& A) {
190  using Teuchos::null;
191  using Teuchos::RCP;
192  using Teuchos::TypeNameTraits;
193  typedef crs_matrix_type MAT;
194  const char prefix[] = "Amesos2::Details::LinearSolver::setMatrix: ";
195 
196  if (A.is_null ()) {
197  solver_ = Teuchos::null;
198  }
199  else {
200  // FIXME (mfh 24 Jul 2015) Even though Amesos2 solvers currently
201  // require a CrsMatrix input, we could add a copy step in order
202  // to let them take a RowMatrix. The issue is that this would
203  // require keeping the original matrix around, and copying again
204  // if it changes.
205  RCP<const MAT> A_mat = Teuchos::rcp_dynamic_cast<const MAT> (A);
206  TEUCHOS_TEST_FOR_EXCEPTION
207  (A_mat.is_null (), std::invalid_argument,
208  "Amesos2::Details::LinearSolver::setMatrix: "
209  "The input matrix A must be a CrsMatrix.");
210  if (solver_.is_null ()) {
211  // Amesos2 solvers must be created with a nonnull matrix.
212  // Thus, we don't actually create the solver until setMatrix
213  // is called for the first time with a nonnull matrix.
214  // Furthermore, Amesos2 solvers do not accept a null matrix
215  // (to setA), so if setMatrix is called with a null matrix, we
216  // free the solver.
217  RCP<solver_type> solver;
218  try {
219  solver = Amesos2::create<MAT, MV> (solverName_, A_mat, null, null);
220  }
221  catch (std::exception& e) {
222  TEUCHOS_TEST_FOR_EXCEPTION
223  (true, std::invalid_argument, prefix << "Failed to create Amesos2 "
224  "solver named \"" << solverName_ << "\". "
225  "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
226  << ", MV = " << TypeNameTraits<MV>::name ()
227  << " threw an exception: " << e.what ());
228  }
229  TEUCHOS_TEST_FOR_EXCEPTION
230  (solver.is_null (), std::invalid_argument, prefix << "Failed to "
231  "create Amesos2 solver named \"" << solverName_ << "\". "
232  "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
233  << ", MV = " << TypeNameTraits<MV>::name ()
234  << " returned null.");
235 
236  // Use same parameters as before, if user set parameters.
237  if (! params_.is_null ()) {
238  solver->setParameters (params_);
239  }
240  solver_ = solver;
241  } else if (A_ != A) {
242  solver_->setA (A_mat);
243  }
244  }
245 
246  // We also have to keep a pointer to A, so that getMatrix() works.
247  A_ = A;
248  }
249 
251  Teuchos::RCP<const OP> getMatrix () const {
252  return A_;
253  }
254 
256  void solve (MV& X, const MV& B) {
257  const char prefix[] = "Amesos2::Details::LinearSolver::solve: ";
258  TEUCHOS_TEST_FOR_EXCEPTION
259  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
260  "exist yet. You must call setMatrix() with a nonnull matrix before you "
261  "may call this method.");
262  TEUCHOS_TEST_FOR_EXCEPTION
263  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
264  "set yet. You must call setMatrix() with a nonnull matrix before you "
265  "may call this method.");
266  solver_->solve (&X, &B);
267  }
268 
270  void setParameters (const Teuchos::RCP<Teuchos::ParameterList>& params) {
271  if (! solver_.is_null ()) {
272  solver_->setParameters (params);
273  }
274  // Remember them, so that if the solver gets recreated, we'll have
275  // the original parameters.
276  params_ = params;
277  }
278 
281  void symbolic () {
282  const char prefix[] = "Amesos2::Details::LinearSolver::symbolic: ";
283  TEUCHOS_TEST_FOR_EXCEPTION
284  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
285  "exist yet. You must call setMatrix() with a nonnull matrix before you "
286  "may call this method.");
287  TEUCHOS_TEST_FOR_EXCEPTION
288  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
289  "set yet. You must call setMatrix() with a nonnull matrix before you "
290  "may call this method.");
291  solver_->symbolicFactorization ();
292  }
293 
296  void numeric () {
297  const char prefix[] = "Amesos2::Details::LinearSolver::numeric: ";
298  TEUCHOS_TEST_FOR_EXCEPTION
299  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
300  "exist yet. You must call setMatrix() with a nonnull matrix before you "
301  "may call this method.");
302  TEUCHOS_TEST_FOR_EXCEPTION
303  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
304  "set yet. You must call setMatrix() with a nonnull matrix before you "
305  "may call this method.");
306  solver_->numericFactorization ();
307  }
308 
310  std::string description () const {
311  using Teuchos::TypeNameTraits;
312  if (solver_.is_null ()) {
313  std::ostringstream os;
314  os << "\"Amesos2::Details::LinearSolver\": {"
315  << "MV: " << TypeNameTraits<MV>::name ()
316  << ", OP: " << TypeNameTraits<OP>::name ()
317  << ", NormType: " << TypeNameTraits<NormType>::name ()
318  << "}";
319  return os.str ();
320  } else {
321  return solver_->description ();
322  }
323  }
324 
326  void
327  describe (Teuchos::FancyOStream& out,
328  const Teuchos::EVerbosityLevel verbLevel =
329  Teuchos::Describable::verbLevel_default) const
330  {
331  using Teuchos::TypeNameTraits;
332  using std::endl;
333  if (solver_.is_null ()) {
334  if (verbLevel > Teuchos::VERB_NONE) {
335  Teuchos::OSTab tab0 (out);
336  out << "\"Amesos2::Details::LinearSolver\":" << endl;
337  Teuchos::OSTab tab1 (out);
338  out << "MV: " << TypeNameTraits<MV>::name () << endl
339  << "OP: " << TypeNameTraits<OP>::name () << endl
340  << "NormType: " << TypeNameTraits<NormType>::name () << endl;
341  }
342  }
343  if (! solver_.is_null ()) {
344  solver_->describe (out, verbLevel);
345  }
346  }
347 
348 private:
349  std::string solverName_;
350  Teuchos::RCP<solver_type> solver_;
351  Teuchos::RCP<const OP> A_;
352  Teuchos::RCP<Teuchos::ParameterList> params_;
353 };
354 
355 template<class MV, class OP, class NormType>
356 Teuchos::RCP<Trilinos::Details::LinearSolver<MV, OP, NormType> >
358 getLinearSolver (const std::string& solverName)
359 {
360  using Teuchos::rcp;
361  return rcp (new Amesos2::Details::LinearSolver<MV, OP, NormType> (solverName));
362 }
363 
364 template<class MV, class OP, class NormType>
365 void
368 {
369 #ifdef HAVE_TEUCHOSCORE_CXX11
370  typedef std::shared_ptr<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
371  //typedef std::shared_ptr<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
372 #else
373  typedef Teuchos::RCP<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
374  //typedef Teuchos::RCP<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
375 #endif // HAVE_TEUCHOSCORE_CXX11
376 
378  Trilinos::Details::registerLinearSolverFactory<MV, OP, NormType> ("Amesos2", factory);
379 }
380 
381 } // namespace Details
382 } // namespace Amesos2
383 
384 // Macro for doing explicit instantiation of
385 // Amesos2::Details::LinearSolverFactory, for Tpetra objects, with
386 // given Tpetra template parameters (SC = Scalar, LO = LocalOrdinal,
387 // GO = GlobalOrdinal, NT = Node).
388 //
389 // We don't have to protect use of Tpetra objects here, or include
390 // any header files for them, because this is a macro definition.
391 #define AMESOS2_DETAILS_LINEARSOLVERFACTORY_INSTANT(SC, LO, GO, NT) \
392  template class Amesos2::Details::LinearSolverFactory<Tpetra::MultiVector<SC, LO, GO, NT>, \
393  Tpetra::Operator<SC, LO, GO, NT>, \
394  typename Tpetra::MultiVector<SC, LO, GO, NT>::mag_type>;
395 
396 #endif // AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
Interface for a &quot;factory&quot; that creates Amesos2 solvers.
Definition: Amesos2_Details_LinearSolverFactory_decl.hpp:43
virtual Teuchos::RCP< Trilinos::Details::LinearSolver< MV, OP, NormType > > getLinearSolver(const std::string &solverName)
Get an instance of a Amesos2 solver.
Definition: Amesos2_Details_LinearSolverFactory_def.hpp:358
Interface to Amesos2 solver objects.
Definition: Amesos2_Solver_decl.hpp:44
static void registerLinearSolverFactory()
Register this LinearSolverFactory with the central registry.
Definition: Amesos2_Details_LinearSolverFactory_def.hpp:367
Contains declarations for Amesos2::create and Amesos2::query.