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 #ifdef HAVE_AMESOS2_EPETRA
59 # include "Epetra_CrsMatrix.h"
60 #endif // HAVE_AMESOS2_EPETRA
61 
62 // mfh 23 Jul 2015: Tpetra is currently a required dependency of Amesos2.
63 #ifndef HAVE_AMESOS2_TPETRA
64 # define HAVE_AMESOS2_TPETRA
65 #endif // HAVE_AMESOS2_TPETRA
66 
67 #ifdef HAVE_AMESOS2_TPETRA
68 # include "Tpetra_CrsMatrix.hpp"
69 #endif // HAVE_AMESOS2_TPETRA
70 
71 namespace Amesos2 {
72 namespace Details {
73 
74 // For a given linear algebra implementation's Operator type OP,
75 // find the corresponding CrsMatrix type.
76 //
77 // Amesos2 unfortunately only does ETI for Tpetra::CrsMatrix, even
78 // though it could very well take Tpetra::RowMatrix.
79 template<class OP>
80 struct GetMatrixType {
81  typedef int type; // flag (see below)
82 
83 #ifdef HAVE_AMESOS2_EPETRA
84  static_assert(! std::is_same<OP, Epetra_MultiVector>::value,
85  "Amesos2::Details::GetMatrixType: OP = Epetra_MultiVector. "
86  "This probably means that you mixed up MV and OP.");
87 #endif // HAVE_AMESOS2_EPETRA
88 
89 #ifdef HAVE_AMESOS2_TPETRA
90  static_assert(! std::is_same<OP, Tpetra::MultiVector<typename OP::scalar_type,
91  typename OP::local_ordinal_type, typename OP::global_ordinal_type,
92  typename OP::node_type> >::value,
93  "Amesos2::Details::GetMatrixType: OP = Tpetra::MultiVector. "
94  "This probably means that you mixed up MV and OP.");
95 #endif // HAVE_AMESOS2_TPETRA
96 };
97 
98 #ifdef HAVE_AMESOS2_EPETRA
99 template<>
100 struct GetMatrixType<Epetra_Operator> {
101  typedef Epetra_CrsMatrix type;
102 };
103 #endif // HAVE_AMESOS2_EPETRA
104 
105 #ifdef HAVE_AMESOS2_TPETRA
106 template<class S, class LO, class GO, class NT>
107 struct GetMatrixType<Tpetra::Operator<S, LO, GO, NT> > {
108  typedef Tpetra::CrsMatrix<S, LO, GO, NT> type;
109 };
110 #endif // HAVE_AMESOS2_TPETRA
111 
112 template<class MV, class OP, class NormType>
113 class LinearSolver :
114  public Trilinos::Details::LinearSolver<MV, OP, NormType>,
115  virtual public Teuchos::Describable
116 {
117 #ifdef HAVE_AMESOS2_EPETRA
118  static_assert(! std::is_same<OP, Epetra_MultiVector>::value,
119  "Amesos2::Details::LinearSolver: OP = Epetra_MultiVector. "
120  "This probably means that you mixed up MV and OP.");
121  static_assert(! std::is_same<MV, Epetra_Operator>::value,
122  "Amesos2::Details::LinearSolver: MV = Epetra_Operator. "
123  "This probably means that you mixed up MV and OP.");
124 #endif // HAVE_AMESOS2_EPETRA
125 
126 public:
133  typedef typename GetMatrixType<OP>::type crs_matrix_type;
134  static_assert(! std::is_same<crs_matrix_type, int>::value,
135  "Amesos2::Details::LinearSolver: The given OP type is not "
136  "supported.");
137 
139  typedef Amesos2::Solver<crs_matrix_type, MV> solver_type;
140 
154  LinearSolver (const std::string& solverName) :
155  solverName_ (solverName)
156  {
157  // FIXME (mfh 25 Aug 2015) Ifpack2::Details::Amesos2Wrapper made
158  // the unfortunate choice to attempt to guess solvers that exist.
159  // Thus, alas, for the sake of backwards compatibility, we must
160  // make an attempt to guess for the user. Furthermore, for strict
161  // backwards compatibility, we should preserve the same (rather
162  // arbitrary) list of choices, in the same order.
163  if (solverName == "") {
164  // KLU2 is the default solver.
165  if (Amesos2::query ("klu2")) {
166  solverName_ = "klu2";
167  }
168  else if (Amesos2::query ("superlu")) {
169  solverName_ = "superlu";
170  }
171  else if (Amesos2::query ("superludist")) {
172  solverName_ = "superludist";
173  }
174  else if (Amesos2::query ("cholmod")) {
175  solverName_ = "cholmod";
176  }
177  else if (Amesos2::query ("basker")) {
178  solverName_ = "basker";
179  }
180  else if (Amesos2::query ("superlumt")) {
181  solverName_ = "superlumt";
182  }
183  else if (Amesos2::query ("pardiso_mkl")) {
184  solverName_ = "pardiso_mkl";
185  }
186  else if (Amesos2::query ("mumps")) {
187  solverName_ = "mumps";
188  }
189  else if (Amesos2::query ("lapack")) {
190  solverName_ = "lapack";
191  }
192  // We don't have to try to rescue the user if their empty solver
193  // name didn't catch any of the above choices.
194  }
195  }
196 
198  virtual ~LinearSolver () {}
199 
204  void setMatrix (const Teuchos::RCP<const OP>& A) {
205  using Teuchos::null;
206  using Teuchos::RCP;
207  using Teuchos::TypeNameTraits;
208  typedef crs_matrix_type MAT;
209  const char prefix[] = "Amesos2::Details::LinearSolver::setMatrix: ";
210 
211  if (A.is_null ()) {
212  solver_ = Teuchos::null;
213  }
214  else {
215  // FIXME (mfh 24 Jul 2015) Even though Amesos2 solvers currently
216  // require a CrsMatrix input, we could add a copy step in order
217  // to let them take a RowMatrix. The issue is that this would
218  // require keeping the original matrix around, and copying again
219  // if it changes.
220  RCP<const MAT> A_mat = Teuchos::rcp_dynamic_cast<const MAT> (A);
221  TEUCHOS_TEST_FOR_EXCEPTION
222  (A_mat.is_null (), std::invalid_argument,
223  "Amesos2::Details::LinearSolver::setMatrix: "
224  "The input matrix A must be a CrsMatrix.");
225  if (solver_.is_null ()) {
226  // Amesos2 solvers must be created with a nonnull matrix.
227  // Thus, we don't actually create the solver until setMatrix
228  // is called for the first time with a nonnull matrix.
229  // Furthermore, Amesos2 solvers do not accept a null matrix
230  // (to setA), so if setMatrix is called with a null matrix, we
231  // free the solver.
232  RCP<solver_type> solver;
233  try {
234  solver = Amesos2::create<MAT, MV> (solverName_, A_mat, null, null);
235  }
236  catch (std::exception& e) {
237  TEUCHOS_TEST_FOR_EXCEPTION
238  (true, std::invalid_argument, prefix << "Failed to create Amesos2 "
239  "solver named \"" << solverName_ << "\". "
240  "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
241  << ", MV = " << TypeNameTraits<MV>::name ()
242  << " threw an exception: " << e.what ());
243  }
244  TEUCHOS_TEST_FOR_EXCEPTION
245  (solver.is_null (), std::invalid_argument, prefix << "Failed to "
246  "create Amesos2 solver named \"" << solverName_ << "\". "
247  "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
248  << ", MV = " << TypeNameTraits<MV>::name ()
249  << " returned null.");
250 
251  // Use same parameters as before, if user set parameters.
252  if (! params_.is_null ()) {
253  solver->setParameters (params_);
254  }
255  solver_ = solver;
256  } else if (A_ != A) {
257  solver_->setA (A_mat);
258  }
259  }
260 
261  // We also have to keep a pointer to A, so that getMatrix() works.
262  A_ = A;
263  }
264 
266  Teuchos::RCP<const OP> getMatrix () const {
267  return A_;
268  }
269 
271  void solve (MV& X, const MV& B) {
272  const char prefix[] = "Amesos2::Details::LinearSolver::solve: ";
273  TEUCHOS_TEST_FOR_EXCEPTION
274  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
275  "exist yet. You must call setMatrix() with a nonnull matrix before you "
276  "may call this method.");
277  TEUCHOS_TEST_FOR_EXCEPTION
278  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
279  "set yet. You must call setMatrix() with a nonnull matrix before you "
280  "may call this method.");
281  solver_->solve (&X, &B);
282  }
283 
285  void setParameters (const Teuchos::RCP<Teuchos::ParameterList>& params) {
286  if (! solver_.is_null ()) {
287  solver_->setParameters (params);
288  }
289  // Remember them, so that if the solver gets recreated, we'll have
290  // the original parameters.
291  params_ = params;
292  }
293 
296  void symbolic () {
297  const char prefix[] = "Amesos2::Details::LinearSolver::symbolic: ";
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_->symbolicFactorization ();
307  }
308 
311  void numeric () {
312  const char prefix[] = "Amesos2::Details::LinearSolver::numeric: ";
313  TEUCHOS_TEST_FOR_EXCEPTION
314  (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
315  "exist yet. You must call setMatrix() with a nonnull matrix before you "
316  "may call this method.");
317  TEUCHOS_TEST_FOR_EXCEPTION
318  (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
319  "set yet. You must call setMatrix() with a nonnull matrix before you "
320  "may call this method.");
321  solver_->numericFactorization ();
322  }
323 
325  std::string description () const {
326  using Teuchos::TypeNameTraits;
327  if (solver_.is_null ()) {
328  std::ostringstream os;
329  os << "\"Amesos2::Details::LinearSolver\": {"
330  << "MV: " << TypeNameTraits<MV>::name ()
331  << ", OP: " << TypeNameTraits<OP>::name ()
332  << ", NormType: " << TypeNameTraits<NormType>::name ()
333  << "}";
334  return os.str ();
335  } else {
336  return solver_->description ();
337  }
338  }
339 
341  void
342  describe (Teuchos::FancyOStream& out,
343  const Teuchos::EVerbosityLevel verbLevel =
344  Teuchos::Describable::verbLevel_default) const
345  {
346  using Teuchos::TypeNameTraits;
347  using std::endl;
348  if (solver_.is_null ()) {
349  if (verbLevel > Teuchos::VERB_NONE) {
350  Teuchos::OSTab tab0 (out);
351  out << "\"Amesos2::Details::LinearSolver\":" << endl;
352  Teuchos::OSTab tab1 (out);
353  out << "MV: " << TypeNameTraits<MV>::name () << endl
354  << "OP: " << TypeNameTraits<OP>::name () << endl
355  << "NormType: " << TypeNameTraits<NormType>::name () << endl;
356  }
357  }
358  if (! solver_.is_null ()) {
359  solver_->describe (out, verbLevel);
360  }
361  }
362 
363 private:
364  std::string solverName_;
365  Teuchos::RCP<solver_type> solver_;
366  Teuchos::RCP<const OP> A_;
367  Teuchos::RCP<Teuchos::ParameterList> params_;
368 };
369 
370 template<class MV, class OP, class NormType>
371 Teuchos::RCP<Trilinos::Details::LinearSolver<MV, OP, NormType> >
373 getLinearSolver (const std::string& solverName)
374 {
375  using Teuchos::rcp;
376  return rcp (new Amesos2::Details::LinearSolver<MV, OP, NormType> (solverName));
377 }
378 
379 template<class MV, class OP, class NormType>
380 void
383 {
384 #ifdef HAVE_TEUCHOSCORE_CXX11
385  typedef std::shared_ptr<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
386  //typedef std::shared_ptr<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
387 #else
388  typedef Teuchos::RCP<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
389  //typedef Teuchos::RCP<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
390 #endif // HAVE_TEUCHOSCORE_CXX11
391 
393  Trilinos::Details::registerLinearSolverFactory<MV, OP, NormType> ("Amesos2", factory);
394 }
395 
396 } // namespace Details
397 } // namespace Amesos2
398 
399 // Macro for doing explicit instantiation of
400 // Amesos2::Details::LinearSolverFactory, for Tpetra objects, with
401 // given Tpetra template parameters (SC = Scalar, LO = LocalOrdinal,
402 // GO = GlobalOrdinal, NT = Node).
403 //
404 // We don't have to protect use of Tpetra objects here, or include
405 // any header files for them, because this is a macro definition.
406 #define AMESOS2_DETAILS_LINEARSOLVERFACTORY_INSTANT(SC, LO, GO, NT) \
407  template class Amesos2::Details::LinearSolverFactory<Tpetra::MultiVector<SC, LO, GO, NT>, \
408  Tpetra::Operator<SC, LO, GO, NT>, \
409  typename Tpetra::MultiVector<SC, LO, GO, NT>::mag_type>;
410 
411 #endif // AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
Interface for a "factory" that creates Amesos2 solvers.
Definition: Amesos2_Details_LinearSolverFactory_decl.hpp:77
Definition: Amesos2_AbstractConcreteMatrixAdapter.hpp:48
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:373
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:382
Contains declarations for Amesos2::create and Amesos2::query.