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 // ***********************************************************************
4 //
5 // Amesos2: Templated Direct Sparse Solver Package
6 // Copyright 2011 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
39 //
40 // ***********************************************************************
41 //
42 // @HEADER
43 
47 
48 #ifndef AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
49 #define AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
50 
51 #include "Amesos2_config.h"
52 #include "Amesos2_Factory.hpp"
53 #include "Amesos2_Solver.hpp"
54 #include "Trilinos_Details_LinearSolver.hpp"
55 #include "Trilinos_Details_LinearSolverFactory.hpp"
56 #include <type_traits>
57 
58 
59 #ifdef HAVE_AMESOS2_EPETRA
60 # include "Epetra_CrsMatrix.h"
61 #endif // HAVE_AMESOS2_EPETRA
62 
63 // mfh 23 Jul 2015: Tpetra is currently a required dependency of Amesos2.
64 #ifndef HAVE_AMESOS2_TPETRA
65 # define HAVE_AMESOS2_TPETRA
66 #endif // HAVE_AMESOS2_TPETRA
67 
68 #ifdef HAVE_AMESOS2_TPETRA
69 # include "Tpetra_CrsMatrix.hpp"
70 #endif // HAVE_AMESOS2_TPETRA
71 
72 namespace Amesos2 {
73 namespace Details {
74 
75 // For a given linear algebra implementation's Operator type OP,
76 // find the corresponding CrsMatrix type.
77 //
78 // Amesos2 unfortunately only does ETI for Tpetra::CrsMatrix, even
79 // though it could very well take Tpetra::RowMatrix.
80 template<class OP>
81 struct GetMatrixType {
82  typedef int type; // flag (see below)
83 
84 
85 #ifdef HAVE_AMESOS2_EPETRA
86  static_assert(! std::is_same<OP, Epetra_MultiVector>::value,
87  "Amesos2::Details::GetMatrixType: OP = Epetra_MultiVector. "
88  "This probably means that you mixed up MV and OP.");
89 #endif // HAVE_AMESOS2_EPETRA
90 
91 #ifdef HAVE_AMESOS2_TPETRA
92  static_assert(! std::is_same<OP, Tpetra::MultiVector<typename OP::scalar_type,
93  typename OP::local_ordinal_type, typename OP::global_ordinal_type,
94  typename OP::node_type> >::value,
95  "Amesos2::Details::GetMatrixType: OP = Tpetra::MultiVector. "
96  "This probably means that you mixed up MV and OP.");
97 #endif // HAVE_AMESOS2_TPETRA
98 };
99 
100 #ifdef HAVE_AMESOS2_EPETRA
101 template<>
102 struct GetMatrixType<Epetra_Operator> {
103  typedef Epetra_CrsMatrix type;
104 };
105 #endif // HAVE_AMESOS2_EPETRA
106 
107 
108 #ifdef HAVE_AMESOS2_TPETRA
109 template<class S, class LO, class GO, class NT>
110 struct GetMatrixType<Tpetra::Operator<S, LO, GO, NT> > {
111  typedef Tpetra::CrsMatrix<S, LO, GO, NT> type;
112 };
113 #endif // HAVE_AMESOS2_TPETRA
114 
115 template<class MV, class OP, class NormType>
116 class LinearSolver :
117  public Trilinos::Details::LinearSolver<MV, OP, NormType>,
118  virtual public Teuchos::Describable
119 {
120 
121 #ifdef HAVE_AMESOS2_EPETRA
122  static_assert(! std::is_same<OP, Epetra_MultiVector>::value,
123  "Amesos2::Details::LinearSolver: OP = Epetra_MultiVector. "
124  "This probably means that you mixed up MV and OP.");
125  static_assert(! std::is_same<MV, Epetra_Operator>::value,
126  "Amesos2::Details::LinearSolver: MV = Epetra_Operator. "
127  "This probably means that you mixed up MV and OP.");
128 #endif // HAVE_AMESOS2_EPETRA
129 
130 public:
137  typedef typename GetMatrixType<OP>::type crs_matrix_type;
138  static_assert(! std::is_same<crs_matrix_type, int>::value,
139  "Amesos2::Details::LinearSolver: The given OP type is not "
140  "supported.");
141 
143  typedef Amesos2::Solver<crs_matrix_type, MV> solver_type;
144 
158  LinearSolver (const std::string& solverName) :
159  solverName_ (solverName)
160  {
161  // FIXME (mfh 25 Aug 2015) Ifpack2::Details::Amesos2Wrapper made
162  // the unfortunate choice to attempt to guess solvers that exist.
163  // Thus, alas, for the sake of backwards compatibility, we must
164  // make an attempt to guess for the user. Furthermore, for strict
165  // backwards compatibility, we should preserve the same (rather
166  // arbitrary) list of choices, in the same order.
167  if (solverName == "") {
168  // KLU2 is the default solver.
169  if (Amesos2::query ("klu2")) {
170  solverName_ = "klu2";
171  }
172  else if (Amesos2::query ("superlu")) {
173  solverName_ = "superlu";
174  }
175  else if (Amesos2::query ("superludist")) {
176  solverName_ = "superludist";
177  }
178  else if (Amesos2::query ("cholmod")) {
179  solverName_ = "cholmod";
180  }
181  else if (Amesos2::query ("basker")) {
182  solverName_ = "basker";
183  }
184  else if (Amesos2::query ("shylubasker")) {
185  solverName_ = "shylubasker";
186  }
187  else if (Amesos2::query ("ShyLUBasker")) {
188  solverName_ = "shylubasker";
189  }
190  else if (Amesos2::query ("superlumt")) {
191  solverName_ = "superlumt";
192  }
193  else if (Amesos2::query ("pardiso_mkl")) {
194  solverName_ = "pardiso_mkl";
195  }
196  else if (Amesos2::query ("mumps")) {
197  solverName_ = "mumps";
198  }
199  else if (Amesos2::query ("lapack")) {
200  solverName_ = "lapack";
201  }
202  else if (Amesos2::query ("umfpack")) {
203  solverName_ = "umfpack";
204  }
205  // We don't have to try to rescue the user if their empty solver
206  // name didn't catch any of the above choices.
207  }
208  }
209 
211  virtual ~LinearSolver () {}
212 
217  void setMatrix (const Teuchos::RCP<const OP>& A) {
218  using Teuchos::null;
219  using Teuchos::RCP;
220  using Teuchos::TypeNameTraits;
221  typedef crs_matrix_type MAT;
222  const char prefix[] = "Amesos2::Details::LinearSolver::setMatrix: ";
223 
224  if (A.is_null ()) {
225  solver_ = Teuchos::null;
226  }
227  else {
228  // FIXME (mfh 24 Jul 2015) Even though Amesos2 solvers currently
229  // require a CrsMatrix input, we could add a copy step in order
230  // to let them take a RowMatrix. The issue is that this would
231  // require keeping the original matrix around, and copying again
232  // if it changes.
233  RCP<const MAT> A_mat = Teuchos::rcp_dynamic_cast<const MAT> (A);
234  TEUCHOS_TEST_FOR_EXCEPTION
235  (A_mat.is_null (), std::invalid_argument,
236  "Amesos2::Details::LinearSolver::setMatrix: "
237  "The input matrix A must be a CrsMatrix.");
238  if (solver_.is_null ()) {
239  // Amesos2 solvers must be created with a nonnull matrix.
240  // Thus, we don't actually create the solver until setMatrix
241  // is called for the first time with a nonnull matrix.
242  // Furthermore, Amesos2 solvers do not accept a null matrix
243  // (to setA), so if setMatrix is called with a null matrix, we
244  // free the solver.
245  RCP<solver_type> solver;
246  try {
247  solver = Amesos2::create<MAT, MV> (solverName_, A_mat, null, null);
248  }
249  catch (std::exception& e) {
250  TEUCHOS_TEST_FOR_EXCEPTION
251  (true, std::invalid_argument, prefix << "Failed to create Amesos2 "
252  "solver named \"" << solverName_ << "\". "
253  "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
254  << ", MV = " << TypeNameTraits<MV>::name ()
255  << " threw an exception: " << e.what ());
256  }
257  TEUCHOS_TEST_FOR_EXCEPTION
258  (solver.is_null (), std::invalid_argument, prefix << "Failed to "
259  "create Amesos2 solver named \"" << solverName_ << "\". "
260  "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
261  << ", MV = " << TypeNameTraits<MV>::name ()
262  << " returned null.");
263 
264  // Use same parameters as before, if user set parameters.
265  if (! params_.is_null ()) {
266  solver->setParameters (params_);
267  }
268  solver_ = solver;
269  } else if (A_ != A) {
270  solver_->setA (A_mat);
271  }
272  }
273 
274  // We also have to keep a pointer to A, so that getMatrix() works.
275  A_ = A;
276  }
277 
279  Teuchos::RCP<const OP> getMatrix () const {
280  return A_;
281  }
282 
284  void solve (MV& X, const MV& B) {
285  const char prefix[] = "Amesos2::Details::LinearSolver::solve: ";
286  TEUCHOS_TEST_FOR_EXCEPTION
287  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
288  "exist yet. You must call setMatrix() with a nonnull matrix before you "
289  "may call this method.");
290  TEUCHOS_TEST_FOR_EXCEPTION
291  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
292  "set yet. You must call setMatrix() with a nonnull matrix before you "
293  "may call this method.");
294  solver_->solve (&X, &B);
295  }
296 
298  void setParameters (const Teuchos::RCP<Teuchos::ParameterList>& params) {
299  if (! solver_.is_null ()) {
300  solver_->setParameters (params);
301  }
302  // Remember them, so that if the solver gets recreated, we'll have
303  // the original parameters.
304  params_ = params;
305  }
306 
309  void symbolic () {
310  const char prefix[] = "Amesos2::Details::LinearSolver::symbolic: ";
311  TEUCHOS_TEST_FOR_EXCEPTION
312  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
313  "exist yet. You must call setMatrix() with a nonnull matrix before you "
314  "may call this method.");
315  TEUCHOS_TEST_FOR_EXCEPTION
316  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
317  "set yet. You must call setMatrix() with a nonnull matrix before you "
318  "may call this method.");
319  solver_->symbolicFactorization ();
320  }
321 
324  void numeric () {
325  const char prefix[] = "Amesos2::Details::LinearSolver::numeric: ";
326  TEUCHOS_TEST_FOR_EXCEPTION
327  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
328  "exist yet. You must call setMatrix() with a nonnull matrix before you "
329  "may call this method.");
330  TEUCHOS_TEST_FOR_EXCEPTION
331  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
332  "set yet. You must call setMatrix() with a nonnull matrix before you "
333  "may call this method.");
334  solver_->numericFactorization ();
335  }
336 
338  std::string description () const {
339  using Teuchos::TypeNameTraits;
340  if (solver_.is_null ()) {
341  std::ostringstream os;
342  os << "\"Amesos2::Details::LinearSolver\": {"
343  << "MV: " << TypeNameTraits<MV>::name ()
344  << ", OP: " << TypeNameTraits<OP>::name ()
345  << ", NormType: " << TypeNameTraits<NormType>::name ()
346  << "}";
347  return os.str ();
348  } else {
349  return solver_->description ();
350  }
351  }
352 
354  void
355  describe (Teuchos::FancyOStream& out,
356  const Teuchos::EVerbosityLevel verbLevel =
357  Teuchos::Describable::verbLevel_default) const
358  {
359  using Teuchos::TypeNameTraits;
360  using std::endl;
361  if (solver_.is_null ()) {
362  if (verbLevel > Teuchos::VERB_NONE) {
363  Teuchos::OSTab tab0 (out);
364  out << "\"Amesos2::Details::LinearSolver\":" << endl;
365  Teuchos::OSTab tab1 (out);
366  out << "MV: " << TypeNameTraits<MV>::name () << endl
367  << "OP: " << TypeNameTraits<OP>::name () << endl
368  << "NormType: " << TypeNameTraits<NormType>::name () << endl;
369  }
370  }
371  if (! solver_.is_null ()) {
372  solver_->describe (out, verbLevel);
373  }
374  }
375 
376 private:
377  std::string solverName_;
378  Teuchos::RCP<solver_type> solver_;
379  Teuchos::RCP<const OP> A_;
380  Teuchos::RCP<Teuchos::ParameterList> params_;
381 };
382 
383 template<class MV, class OP, class NormType>
384 Teuchos::RCP<Trilinos::Details::LinearSolver<MV, OP, NormType> >
386 getLinearSolver (const std::string& solverName)
387 {
388  using Teuchos::rcp;
389  return rcp (new Amesos2::Details::LinearSolver<MV, OP, NormType> (solverName));
390 }
391 
392 template<class MV, class OP, class NormType>
393 void
396 {
397 #ifdef HAVE_TEUCHOSCORE_CXX11
398  typedef std::shared_ptr<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
399  //typedef std::shared_ptr<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
400 #else
401  typedef Teuchos::RCP<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
402  //typedef Teuchos::RCP<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
403 #endif // HAVE_TEUCHOSCORE_CXX11
404 
406  Trilinos::Details::registerLinearSolverFactory<MV, OP, NormType> ("Amesos2", factory);
407 }
408 
409 } // namespace Details
410 } // namespace Amesos2
411 
412 // Macro for doing explicit instantiation of
413 // Amesos2::Details::LinearSolverFactory, for Tpetra objects, with
414 // given Tpetra template parameters (SC = Scalar, LO = LocalOrdinal,
415 // GO = GlobalOrdinal, NT = Node).
416 //
417 // We don't have to protect use of Tpetra objects here, or include
418 // any header files for them, because this is a macro definition.
419 #define AMESOS2_DETAILS_LINEARSOLVERFACTORY_INSTANT(SC, LO, GO, NT) \
420  template class Amesos2::Details::LinearSolverFactory<Tpetra::MultiVector<SC, LO, GO, NT>, \
421  Tpetra::Operator<SC, LO, GO, NT>, \
422  typename Tpetra::MultiVector<SC, LO, GO, NT>::mag_type>;
423 
424 #endif // AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
Interface for a &quot;factory&quot; that creates Amesos2 solvers.
Definition: Amesos2_Details_LinearSolverFactory_decl.hpp:77
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:386
Interface to Amesos2 solver objects.
Definition: Amesos2_Solver_decl.hpp:78
static void registerLinearSolverFactory()
Register this LinearSolverFactory with the central registry.
Definition: Amesos2_Details_LinearSolverFactory_def.hpp:395
Contains declarations for Amesos2::create and Amesos2::query.