MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_DirectSolver_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_DIRECTSOLVER_DEF_HPP
11 #define MUELU_DIRECTSOLVER_DEF_HPP
12 
13 #include <Xpetra_Utils.hpp>
14 #include <Xpetra_Matrix.hpp>
15 
17 
18 #include "MueLu_Exceptions.hpp"
19 #include "MueLu_Level.hpp"
20 
21 #include "MueLu_Amesos2Smoother.hpp"
22 #include "MueLu_AmesosSmoother.hpp"
23 #include "MueLu_BelosSmoother.hpp"
24 #include "MueLu_StratimikosSmoother.hpp"
25 #include "MueLu_RefMaxwellSmoother.hpp"
26 
27 namespace MueLu {
28 
29 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31  : type_(type) {
32  // The original idea behind all smoothers was to use prototype pattern. However, it does not fully work of the dependencies
33  // calculation. Particularly, we need to propagate DeclareInput to proper prototypes. Therefore, both TrilinosSmoother and
34  // DirectSolver do not follow the pattern exactly.
35  // The difference is that in order to propagate the calculation of dependencies, we need to call a DeclareInput on a
36  // constructed object (or objects, as we have two different code branches for Epetra and Tpetra). The only place where we
37  // could construct these objects is the constructor. Thus, we need to store RCPs, and both TrilinosSmoother and DirectSolver
38  // obtain a state: they contain RCP to smoother prototypes.
39  sEpetra_ = Teuchos::null;
40  sTpetra_ = Teuchos::null;
41  sBelos_ = Teuchos::null;
42 
43  ParameterList paramList = paramListIn;
44 
45  // We want DirectSolver to be able to work with both Epetra and Tpetra objects, therefore we try to construct both
46  // Amesos and Amesos2 solver prototypes. The construction really depends on configuration options.
47  triedEpetra_ = triedTpetra_ = false;
48 #if defined(HAVE_MUELU_AMESOS2)
49  try {
50  sTpetra_ = rcp(new Amesos2Smoother(type_, paramList));
51  if (sTpetra_.is_null())
52  errorTpetra_ = "Unable to construct Amesos2 direct solver";
53  else if (!sTpetra_->constructionSuccessful()) {
54  errorTpetra_ = sTpetra_->constructionErrorMsg();
55  sTpetra_ = Teuchos::null;
56  }
57  } catch (Exceptions::RuntimeError& e) {
58  errorTpetra_ = e.what();
59  } catch (Exceptions::BadCast& e) {
60  errorTpetra_ = e.what();
62  errorTpetra_ = e.what();
63  }
64  triedTpetra_ = true;
65 #endif
66 #if defined(HAVE_MUELU_EPETRA) && defined(HAVE_MUELU_AMESOS)
67  try {
68  // GetAmesosSmoother masks the template argument matching, and simply throws if template arguments are incompatible with Epetra
69  sEpetra_ = GetAmesosSmoother<SC, LO, GO, NO>(type_, paramList);
70  if (sEpetra_.is_null())
71  errorEpetra_ = "Unable to construct Amesos direct solver";
72  else if (!sEpetra_->constructionSuccessful()) {
73  errorEpetra_ = sEpetra_->constructionErrorMsg();
74  sEpetra_ = Teuchos::null;
75  }
76  } catch (Exceptions::RuntimeError& e) {
77  // AmesosSmoother throws if Scalar != double, LocalOrdinal != int, GlobalOrdinal != int
78  errorEpetra_ = e.what();
79  }
80  triedEpetra_ = true;
81 #endif
82 #if defined(HAVE_MUELU_BELOS)
83  try {
84  sBelos_ = rcp(new BelosSmoother(type_, paramList));
85  if (sBelos_.is_null())
86  errorBelos_ = "Unable to construct Belos solver";
87  else if (!sBelos_->constructionSuccessful()) {
88  errorBelos_ = sBelos_->constructionErrorMsg();
89  sBelos_ = Teuchos::null;
90  }
91  } catch (Exceptions::RuntimeError& e) {
92  errorBelos_ = e.what();
93  } catch (Exceptions::BadCast& e) {
94  errorBelos_ = e.what();
95  }
96  triedBelos_ = true;
97 #endif
98 #if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
99  try {
100  sStratimikos_ = rcp(new StratimikosSmoother(type_, paramList));
101  if (sStratimikos_.is_null())
102  errorStratimikos_ = "Unable to construct Stratimikos smoother";
103  else if (!sStratimikos_->constructionSuccessful()) {
104  errorStratimikos_ = sStratimikos_->constructionErrorMsg();
105  sStratimikos_ = Teuchos::null;
106  }
107  } catch (Exceptions::RuntimeError& e) {
108  errorStratimikos_ = e.what();
109  }
110  triedStratimikos_ = true;
111 #endif
112  try {
113  sRefMaxwell_ = rcp(new RefMaxwellSmoother(type_, paramList));
114  if (sRefMaxwell_.is_null())
115  errorRefMaxwell_ = "Unable to construct RefMaxwell smoother";
116  else if (!sRefMaxwell_->constructionSuccessful()) {
117  errorRefMaxwell_ = sRefMaxwell_->constructionErrorMsg();
118  sRefMaxwell_ = Teuchos::null;
119  }
120  } catch (Exceptions::RuntimeError& e) {
121  errorRefMaxwell_ = e.what();
122  }
123  triedRefMaxwell_ = true;
124 
125  // Check if we were able to construct at least one solver. In many cases that's all we need, for instance if a user
126  // simply wants to use Tpetra only stack, never enables Amesos, and always runs Tpetra objects.
128  "Unable to construct any direct solver."
129  "Plase enable (TPETRA and AMESOS2) or (EPETRA and AMESOS) or (BELOS) or (STRATIMIKOS)");
130 
131  TEUCHOS_TEST_FOR_EXCEPTION(sEpetra_.is_null() && sTpetra_.is_null() && sBelos_.is_null() && sStratimikos_.is_null() && sRefMaxwell_.is_null(), Exceptions::RuntimeError,
132  "Could not enable any direct solver:\n"
133  << (triedEpetra_ ? "Epetra mode was disabled due to an error:\n" : "")
134  << (triedEpetra_ ? errorEpetra_ : "")
135  << (triedTpetra_ ? "Tpetra mode was disabled due to an error:\n" : "")
136  << (triedTpetra_ ? errorTpetra_ : "")
137  << (triedBelos_ ? "Belos was disabled due to an error:\n" : "")
138  << (triedBelos_ ? errorBelos_ : "")
139  << (triedStratimikos_ ? "Stratimikos was disabled due to an error:\n" : "")
141  << (triedRefMaxwell_ ? "RefMaxwell was disabled due to an error:\n" : "")
142  << (triedRefMaxwell_ ? errorRefMaxwell_ : ""));
143  ;
144 
145  this->SetParameterList(paramList);
146 }
147 
148 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
150  // We need to propagate SetFactory to proper place
151  if (!sEpetra_.is_null()) sEpetra_->SetFactory(varName, factory);
152  if (!sTpetra_.is_null()) sTpetra_->SetFactory(varName, factory);
153  if (!sBelos_.is_null()) sBelos_->SetFactory(varName, factory);
154  if (!sStratimikos_.is_null()) sStratimikos_->SetFactory(varName, factory);
155  if (!sRefMaxwell_.is_null()) sRefMaxwell_->SetFactory(varName, factory);
156 }
157 
158 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
160  if (!sBelos_.is_null())
161  s_ = sBelos_;
162  else if (!sStratimikos_.is_null())
163  s_ = sStratimikos_;
164  else if (!sRefMaxwell_.is_null())
165  s_ = sRefMaxwell_;
166  else {
167  // Decide whether we are running in Epetra or Tpetra mode
168  //
169  // Theoretically, we could make this decision in the constructor, and create only
170  // one of the smoothers. But we want to be able to reuse, so one can imagine a scenario
171  // where one first runs hierarchy with tpetra matrix, and then with epetra.
172  bool useTpetra = (currentLevel.lib() == Xpetra::UseTpetra);
173  s_ = (useTpetra ? sTpetra_ : sEpetra_);
174  if (s_.is_null()) {
175  if (useTpetra) {
176 #if not defined(HAVE_MUELU_AMESOS2)
178  "Error: running in Tpetra mode, but MueLu with Amesos2 was disabled during the configure stage.\n"
179  "Please make sure that:\n"
180  " - Amesos2 is enabled (Trilinos_ENABLE_Amesos2=ON),\n"
181  " - Amesos2 is available for MueLu to use (MueLu_ENABLE_Amesos2=ON)\n");
182 #else
183  if (triedTpetra_)
184  this->GetOStream(Errors) << "Tpetra mode was disabled due to an error:\n"
185  << errorTpetra_ << std::endl;
186 #endif
187  }
188  if (!useTpetra) {
189 #if not defined(HAVE_MUELU_AMESOS)
191  "Error: running in Epetra mode, but MueLu with Amesos was disabled during the configure stage.\n"
192  "Please make sure that:\n"
193  " - Amesos is enabled (you can do that with Trilinos_ENABLE_Amesos=ON),\n"
194  " - Amesos is available for MueLu to use (MueLu_ENABLE_Amesos=ON)\n");
195 #else
196  if (triedEpetra_)
197  this->GetOStream(Errors) << "Epetra mode was disabled due to an error:\n"
198  << errorEpetra_ << std::endl;
199 #endif
200  }
202  "Direct solver for " << (useTpetra ? "Tpetra" : "Epetra") << " was not constructed");
203  }
204  }
205 
206  s_->DeclareInput(currentLevel);
207 }
208 
209 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
211  if (SmootherPrototype::IsSetup() == true)
212  this->GetOStream(Warnings0) << "MueLu::DirectSolver::Setup(): Setup() has already been called" << std::endl;
213 
214  int oldRank = s_->SetProcRankVerbose(this->GetProcRankVerbose());
215 
216  s_->Setup(currentLevel);
217 
218  s_->SetProcRankVerbose(oldRank);
219 
221 
222  this->SetParameterList(s_->GetParameterList());
223 }
224 
225 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
226 void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
227  TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::AmesosSmoother::Apply(): Setup() has not been called");
228 
229  s_->Apply(X, B, InitialGuessIsZero);
230 }
231 
232 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
234  RCP<DirectSolver> newSmoo = rcp(new DirectSolver(*this));
235 
236  // We need to be quite careful with Copy
237  // We still want DirectSolver to follow Prototype Pattern, so we need to hide the fact that we do have some state
238  if (!sEpetra_.is_null())
239  newSmoo->sEpetra_ = sEpetra_->Copy();
240  if (!sTpetra_.is_null())
241  newSmoo->sTpetra_ = sTpetra_->Copy();
242  if (!sBelos_.is_null())
243  newSmoo->sBelos_ = sBelos_->Copy();
244  if (!sStratimikos_.is_null())
245  newSmoo->sStratimikos_ = sStratimikos_->Copy();
246  if (!sRefMaxwell_.is_null())
247  newSmoo->sRefMaxwell_ = sRefMaxwell_->Copy();
248 
249  // Copy the default mode
250  if (s_.get() == sBelos_.get())
251  newSmoo->s_ = newSmoo->sBelos_;
252  else if (s_.get() == sStratimikos_.get())
253  newSmoo->s_ = newSmoo->sStratimikos_;
254  else if (s_.get() == sRefMaxwell_.get())
255  newSmoo->s_ = newSmoo->sRefMaxwell_;
256  else if (s_.get() == sTpetra_.get())
257  newSmoo->s_ = newSmoo->sTpetra_;
258  else
259  newSmoo->s_ = newSmoo->sEpetra_;
260  newSmoo->SetParameterList(this->GetParameterList());
261 
262  return newSmoo;
263 }
264 
265 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
267  std::ostringstream out;
268  if (s_ != Teuchos::null) {
269  out << s_->description();
270  } else {
272  out << "{type = " << type_ << "}";
273  }
274  return out.str();
275 }
276 
277 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
280 
281  if (verbLevel & Parameters0)
282  out0 << "Prec. type: " << type_ << std::endl;
283 
284  if (verbLevel & Parameters1) {
285  out0 << "Parameter list: " << std::endl;
286  Teuchos::OSTab tab3(out);
287  out << this->GetParameterList();
288  }
289 
290  if (verbLevel & Debug)
291  out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
292 }
293 
294 } // namespace MueLu
295 
296 #endif // MUELU_DIRECTSOLVER_DEF_HPP
Important warning messages (one line)
Exception indicating invalid cast attempted.
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
DirectSolver cannot be applied. Apply() always returns a RuntimeError exception.
void Setup(Level &currentLevel)
DirectSolver cannot be turned into a smoother using Setup(). Setup() always returns a RuntimeError ex...
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void DeclareInput(Level &currentLevel) const
Input.
Class that encapsulates Belos smoothers.
Print additional debugging information.
std::string type_
amesos1/2-specific key phrase that denote smoother type
DirectSolver(const std::string &type="", const Teuchos::ParameterList &paramList=Teuchos::ParameterList())
Constructor Note: only parameters shared by Amesos and Amesos2 should be used for type and paramList ...
Class that encapsulates direct solvers. Autoselection of AmesosSmoother or Amesos2Smoother according ...
RCP< SmootherPrototype > Copy() const
When this prototype is cloned using Copy(), the clone is an Amesos or an Amesos2 smoother.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
virtual void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
std::string description() const
Return a simple one-line description of this object.
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
Class that encapsulates Amesos2 direct solvers.
RCP< SmootherPrototype > sBelos_
bool IsSetup() const
Get the state of a smoother prototype.
Xpetra::UnderlyingLib lib()
Class that encapsulates Operator smoothers.
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
RCP< SmootherPrototype > sTpetra_
Print class parameters.
void SetFactory(const std::string &varName, const RCP< const FactoryBase > &factory)
Custom SetFactory.
RCP< SmootherPrototype > sEpetra_
Smoother.
RCP< SmootherPrototype > sRefMaxwell_
RCP< SmootherPrototype > s_
Print class parameters (more parameters, more verbose)
Exception throws to report errors in the internal logical of the program.
RCP< SmootherPrototype > sStratimikos_
virtual std::string description() const
Return a simple one-line description of this object.
std::string toString(const T &t)