MueLu Version of the Day
Loading...
Searching...
No Matches
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"
23#include "MueLu_BelosSmoother.hpp"
24#include "MueLu_StratimikosSmoother.hpp"
25#include "MueLu_RefMaxwellSmoother.hpp"
26
27namespace MueLu {
28
29template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
30DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::DirectSolver(const std::string& type, const Teuchos::ParameterList& paramListIn)
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();
61 } catch (Teuchos::Exceptions::InvalidParameterName& e) {
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" : "")
143 ;
144
145 this->SetParameterList(paramList);
146}
147
148template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
149void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::SetFactory(const std::string& varName, const RCP<const FactoryBase>& factory) {
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
158template <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)
177 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
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)
190 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
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 }
201 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
202 "Direct solver for " << (useTpetra ? "Tpetra" : "Epetra") << " was not constructed");
203 }
204 }
205
206 s_->DeclareInput(currentLevel);
207}
208
209template <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
225template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
226void 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
232template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
233RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> > DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Copy() const {
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
265template <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
277template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
278void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream& out, const VerbLevel verbLevel) const {
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
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
Class that encapsulates Amesos2 direct solvers.
Class that encapsulates Belos smoothers.
virtual std::string description() const
Return a simple one-line description of this object.
Class that encapsulates direct solvers. Autoselection of AmesosSmoother or Amesos2Smoother according ...
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
DirectSolver cannot be applied. Apply() always returns a RuntimeError exception.
std::string description() const
Return a simple one-line description of this object.
void Setup(Level &currentLevel)
DirectSolver cannot be turned into a smoother using Setup(). Setup() always returns a RuntimeError ex...
void SetFactory(const std::string &varName, const RCP< const FactoryBase > &factory)
Custom SetFactory.
RCP< SmootherPrototype > sBelos_
RCP< SmootherPrototype > sStratimikos_
RCP< SmootherPrototype > sEpetra_
Smoother.
RCP< SmootherPrototype > sRefMaxwell_
void DeclareInput(Level &currentLevel) const
Input.
RCP< SmootherPrototype > Copy() const
When this prototype is cloned using Copy(), the clone is an Amesos or an Amesos2 smoother.
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 ...
RCP< SmootherPrototype > sTpetra_
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
Class that holds all level-specific information.
Xpetra::UnderlyingLib lib()
virtual void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
Class that encapsulates Operator smoothers.
bool IsSetup() const
Get the state of a smoother prototype.
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line)
@ Debug
Print additional debugging information.
@ Parameters0
Print class parameters.
@ Parameters1
Print class parameters (more parameters, more verbose)