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// mfh 23 Jul 2015: Tpetra is currently a required dependency of Amesos2.
26#ifndef HAVE_AMESOS2_TPETRA
27# define HAVE_AMESOS2_TPETRA
28#endif // HAVE_AMESOS2_TPETRA
29
30#ifdef HAVE_AMESOS2_TPETRA
31# include "Tpetra_CrsMatrix.hpp"
32#endif // HAVE_AMESOS2_TPETRA
33
34namespace Amesos2 {
35namespace Details {
36
37// For a given linear algebra implementation's Operator type OP,
38// find the corresponding CrsMatrix type.
39//
40// Amesos2 unfortunately only does ETI for Tpetra::CrsMatrix, even
41// though it could very well take Tpetra::RowMatrix.
42template<class OP>
43struct GetMatrixType {
44 typedef int type; // flag (see below)
45
46#ifdef HAVE_AMESOS2_TPETRA
47 static_assert(! std::is_same<OP, Tpetra::MultiVector<typename OP::scalar_type,
48 typename OP::local_ordinal_type, typename OP::global_ordinal_type,
49 typename OP::node_type> >::value,
50 "Amesos2::Details::GetMatrixType: OP = Tpetra::MultiVector. "
51 "This probably means that you mixed up MV and OP.");
52#endif // HAVE_AMESOS2_TPETRA
53};
54
55#ifdef HAVE_AMESOS2_TPETRA
56template<class S, class LO, class GO, class NT>
57struct GetMatrixType<Tpetra::Operator<S, LO, GO, NT> > {
58 typedef Tpetra::CrsMatrix<S, LO, GO, NT> type;
59};
60#endif // HAVE_AMESOS2_TPETRA
61
62template<class MV, class OP, class NormType>
63class LinearSolver :
64 public Trilinos::Details::LinearSolver<MV, OP, NormType>,
65 virtual public Teuchos::Describable
66{
67
68public:
75 typedef typename GetMatrixType<OP>::type crs_matrix_type;
76 static_assert(! std::is_same<crs_matrix_type, int>::value,
77 "Amesos2::Details::LinearSolver: The given OP type is not "
78 "supported.");
79
81 typedef Amesos2::Solver<crs_matrix_type, MV> solver_type;
82
96 LinearSolver (const std::string& solverName) :
97 solverName_ (solverName)
98 {
99 // FIXME (mfh 25 Aug 2015) Ifpack2::Details::Amesos2Wrapper made
100 // the unfortunate choice to attempt to guess solvers that exist.
101 // Thus, alas, for the sake of backwards compatibility, we must
102 // make an attempt to guess for the user. Furthermore, for strict
103 // backwards compatibility, we should preserve the same (rather
104 // arbitrary) list of choices, in the same order.
105 if (solverName == "") {
106 // KLU2 is the default solver.
107 if (Amesos2::query ("klu2")) {
108 solverName_ = "klu2";
109 }
110 else if (Amesos2::query ("superlu")) {
111 solverName_ = "superlu";
112 }
113 else if (Amesos2::query ("superludist")) {
114 solverName_ = "superludist";
115 }
116 else if (Amesos2::query ("cholmod")) {
117 solverName_ = "cholmod";
118 }
119 else if (Amesos2::query ("cusolver")) {
120 solverName_ = "cusolver";
121 }
122 else if (Amesos2::query ("basker")) {
123 solverName_ = "basker";
124 }
125 else if (Amesos2::query ("shylubasker")) {
126 solverName_ = "shylubasker";
127 }
128 else if (Amesos2::query ("ShyLUBasker")) {
129 solverName_ = "shylubasker";
130 }
131 else if (Amesos2::query ("superlumt")) {
132 solverName_ = "superlumt";
133 }
134 else if (Amesos2::query ("pardiso_mkl")) {
135 solverName_ = "pardiso_mkl";
136 }
137 else if (Amesos2::query ("css_mkl")) {
138 solverName_ = "css_mkl";
139 }
140 else if (Amesos2::query ("mumps")) {
141 solverName_ = "mumps";
142 }
143 else if (Amesos2::query ("lapack")) {
144 solverName_ = "lapack";
145 }
146 else if (Amesos2::query ("umfpack")) {
147 solverName_ = "umfpack";
148 }
149 else if (Amesos2::query ("tacho")) {
150 solverName_ = "tacho";
151 }
152 // We don't have to try to rescue the user if their empty solver
153 // name didn't catch any of the above choices.
154 }
155 }
156
158 virtual ~LinearSolver () {}
159
164 void setMatrix (const Teuchos::RCP<const OP>& A) {
165 using Teuchos::null;
166 using Teuchos::RCP;
167 using Teuchos::TypeNameTraits;
168 typedef crs_matrix_type MAT;
169 const char prefix[] = "Amesos2::Details::LinearSolver::setMatrix: ";
170
171 if (A.is_null ()) {
172 solver_ = Teuchos::null;
173 }
174 else {
175 // FIXME (mfh 24 Jul 2015) Even though Amesos2 solvers currently
176 // require a CrsMatrix input, we could add a copy step in order
177 // to let them take a RowMatrix. The issue is that this would
178 // require keeping the original matrix around, and copying again
179 // if it changes.
180 RCP<const MAT> A_mat = Teuchos::rcp_dynamic_cast<const MAT> (A);
181 TEUCHOS_TEST_FOR_EXCEPTION
182 (A_mat.is_null (), std::invalid_argument,
183 "Amesos2::Details::LinearSolver::setMatrix: "
184 "The input matrix A must be a CrsMatrix.");
185 if (solver_.is_null ()) {
186 // Amesos2 solvers must be created with a nonnull matrix.
187 // Thus, we don't actually create the solver until setMatrix
188 // is called for the first time with a nonnull matrix.
189 // Furthermore, Amesos2 solvers do not accept a null matrix
190 // (to setA), so if setMatrix is called with a null matrix, we
191 // free the solver.
192 RCP<solver_type> solver;
193 try {
194 solver = Amesos2::create<MAT, MV> (solverName_, A_mat, null, null);
195 }
196 catch (std::exception& e) {
197 TEUCHOS_TEST_FOR_EXCEPTION
198 (true, std::invalid_argument, prefix << "Failed to create Amesos2 "
199 "solver named \"" << solverName_ << "\". "
200 "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
201 << ", MV = " << TypeNameTraits<MV>::name ()
202 << " threw an exception: " << e.what ());
203 }
204 TEUCHOS_TEST_FOR_EXCEPTION
205 (solver.is_null (), std::invalid_argument, prefix << "Failed to "
206 "create Amesos2 solver named \"" << solverName_ << "\". "
207 "Amesos2::create<MAT = " << TypeNameTraits<MAT>::name ()
208 << ", MV = " << TypeNameTraits<MV>::name ()
209 << " returned null.");
210
211 // Use same parameters as before, if user set parameters.
212 if (! params_.is_null ()) {
213 solver->setParameters (params_);
214 }
215 solver_ = solver;
216 } else if (A_ != A) {
217 solver_->setA (A_mat);
218 }
219 }
220
221 // We also have to keep a pointer to A, so that getMatrix() works.
222 A_ = A;
223 }
224
226 Teuchos::RCP<const OP> getMatrix () const {
227 return A_;
228 }
229
231 void solve (MV& X, const MV& B) {
232 const char prefix[] = "Amesos2::Details::LinearSolver::solve: ";
233 TEUCHOS_TEST_FOR_EXCEPTION
234 (solver_.is_null (), std::runtime_error, prefix << "The solver does not "
235 "exist yet. You must call setMatrix() with a nonnull matrix before you "
236 "may call this method.");
237 TEUCHOS_TEST_FOR_EXCEPTION
238 (A_.is_null (), std::runtime_error, prefix << "The matrix has not been "
239 "set yet. You must call setMatrix() with a nonnull matrix before you "
240 "may call this method.");
241 solver_->solve (&X, &B);
242 }
243
245 void setParameters (const Teuchos::RCP<Teuchos::ParameterList>& params) {
246 if (! solver_.is_null ()) {
247 solver_->setParameters (params);
248 }
249 // Remember them, so that if the solver gets recreated, we'll have
250 // the original parameters.
251 params_ = params;
252 }
253
256 void symbolic () {
257 const char prefix[] = "Amesos2::Details::LinearSolver::symbolic: ";
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_->symbolicFactorization ();
267 }
268
271 void numeric () {
272 const char prefix[] = "Amesos2::Details::LinearSolver::numeric: ";
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_->numericFactorization ();
282 }
283
285 std::string description () const {
286 using Teuchos::TypeNameTraits;
287 if (solver_.is_null ()) {
288 std::ostringstream os;
289 os << "\"Amesos2::Details::LinearSolver\": {"
290 << "MV: " << TypeNameTraits<MV>::name ()
291 << ", OP: " << TypeNameTraits<OP>::name ()
292 << ", NormType: " << TypeNameTraits<NormType>::name ()
293 << "}";
294 return os.str ();
295 } else {
296 return solver_->description ();
297 }
298 }
299
301 void
302 describe (Teuchos::FancyOStream& out,
303 const Teuchos::EVerbosityLevel verbLevel =
304 Teuchos::Describable::verbLevel_default) const
305 {
306 using Teuchos::TypeNameTraits;
307 using std::endl;
308 if (solver_.is_null ()) {
309 if (verbLevel > Teuchos::VERB_NONE) {
310 Teuchos::OSTab tab0 (out);
311 out << "\"Amesos2::Details::LinearSolver\":" << endl;
312 Teuchos::OSTab tab1 (out);
313 out << "MV: " << TypeNameTraits<MV>::name () << endl
314 << "OP: " << TypeNameTraits<OP>::name () << endl
315 << "NormType: " << TypeNameTraits<NormType>::name () << endl;
316 }
317 }
318 if (! solver_.is_null ()) {
319 solver_->describe (out, verbLevel);
320 }
321 }
322
323private:
324 std::string solverName_;
325 Teuchos::RCP<solver_type> solver_;
326 Teuchos::RCP<const OP> A_;
327 Teuchos::RCP<Teuchos::ParameterList> params_;
328};
329
330template<class MV, class OP, class NormType>
331Teuchos::RCP<Trilinos::Details::LinearSolver<MV, OP, NormType> >
333getLinearSolver (const std::string& solverName)
334{
335 using Teuchos::rcp;
336 return rcp (new Amesos2::Details::LinearSolver<MV, OP, NormType> (solverName));
337}
338
339template<class MV, class OP, class NormType>
340void
343{
344#ifdef HAVE_TEUCHOSCORE_CXX11
345 typedef std::shared_ptr<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
346 //typedef std::shared_ptr<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
347#else
348 typedef Teuchos::RCP<Amesos2::Details::LinearSolverFactory<MV, OP, NormType> > ptr_type;
349 //typedef Teuchos::RCP<Trilinos::Details::LinearSolverFactory<MV, OP> > base_ptr_type;
350#endif // HAVE_TEUCHOSCORE_CXX11
351
353 Trilinos::Details::registerLinearSolverFactory<MV, OP, NormType> ("Amesos2", factory);
354}
355
356} // namespace Details
357} // namespace Amesos2
358
359// Macro for doing explicit instantiation of
360// Amesos2::Details::LinearSolverFactory, for Tpetra objects, with
361// given Tpetra template parameters (SC = Scalar, LO = LocalOrdinal,
362// GO = GlobalOrdinal, NT = Node).
363//
364// We don't have to protect use of Tpetra objects here, or include
365// any header files for them, because this is a macro definition.
366#define AMESOS2_DETAILS_LINEARSOLVERFACTORY_INSTANT(SC, LO, GO, NT) \
367 template class Amesos2::Details::LinearSolverFactory<Tpetra::MultiVector<SC, LO, GO, NT>, \
368 Tpetra::Operator<SC, LO, GO, NT>, \
369 typename Tpetra::MultiVector<SC, LO, GO, NT>::mag_type>;
370
371#endif // AMESOS2_DETAILS_LINEARSOLVERFACTORY_DEF_HPP
Contains declarations for Amesos2::create and Amesos2::query.
Interface for a "factory" that creates Amesos2 solvers.
Definition Amesos2_Details_LinearSolverFactory_decl.hpp:44
static void registerLinearSolverFactory()
Register this LinearSolverFactory with the central registry.
Definition Amesos2_Details_LinearSolverFactory_def.hpp:342
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:333
Interface to Amesos2 solver objects.
Definition Amesos2_Solver_decl.hpp:44