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 try {
49 sTpetra_ = rcp(new Amesos2Smoother(type_, paramList));
50 if (sTpetra_.is_null())
51 errorTpetra_ = "Unable to construct Amesos2 direct solver";
52 else if (!sTpetra_->constructionSuccessful()) {
53 errorTpetra_ = sTpetra_->constructionErrorMsg();
54 sTpetra_ = Teuchos::null;
55 }
56 } catch (Exceptions::RuntimeError& e) {
57 errorTpetra_ = e.what();
58 } catch (Exceptions::BadCast& e) {
59 errorTpetra_ = e.what();
60 } catch (Teuchos::Exceptions::InvalidParameterName& e) {
61 errorTpetra_ = e.what();
62 }
63 triedTpetra_ = true;
64#if defined(HAVE_MUELU_BELOS)
65 try {
66 sBelos_ = rcp(new BelosSmoother(type_, paramList));
67 if (sBelos_.is_null())
68 errorBelos_ = "Unable to construct Belos solver";
69 else if (!sBelos_->constructionSuccessful()) {
70 errorBelos_ = sBelos_->constructionErrorMsg();
71 sBelos_ = Teuchos::null;
72 }
73 } catch (Exceptions::RuntimeError& e) {
74 errorBelos_ = e.what();
75 } catch (Exceptions::BadCast& e) {
76 errorBelos_ = e.what();
77 }
78 triedBelos_ = true;
79#endif
80#if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
81 try {
82 sStratimikos_ = rcp(new StratimikosSmoother(type_, paramList));
83 if (sStratimikos_.is_null())
84 errorStratimikos_ = "Unable to construct Stratimikos smoother";
85 else if (!sStratimikos_->constructionSuccessful()) {
86 errorStratimikos_ = sStratimikos_->constructionErrorMsg();
87 sStratimikos_ = Teuchos::null;
88 }
89 } catch (Exceptions::RuntimeError& e) {
90 errorStratimikos_ = e.what();
91 }
92 triedStratimikos_ = true;
93#endif
94 try {
95 sRefMaxwell_ = rcp(new RefMaxwellSmoother(type_, paramList));
96 if (sRefMaxwell_.is_null())
97 errorRefMaxwell_ = "Unable to construct RefMaxwell smoother";
98 else if (!sRefMaxwell_->constructionSuccessful()) {
99 errorRefMaxwell_ = sRefMaxwell_->constructionErrorMsg();
100 sRefMaxwell_ = Teuchos::null;
101 }
102 } catch (Exceptions::RuntimeError& e) {
103 errorRefMaxwell_ = e.what();
104 }
105 triedRefMaxwell_ = true;
106
107 // Check if we were able to construct at least one solver. In many cases that's all we need, for instance if a user
108 // simply wants to use Tpetra only stack, never enables Amesos, and always runs Tpetra objects.
110 "Unable to construct any direct solver."
111 "Plase enable (TPETRA and AMESOS2) or (EPETRA and AMESOS) or (BELOS) or (STRATIMIKOS)");
112
113 TEUCHOS_TEST_FOR_EXCEPTION(sEpetra_.is_null() && sTpetra_.is_null() && sBelos_.is_null() && sStratimikos_.is_null() && sRefMaxwell_.is_null(), Exceptions::RuntimeError,
114 "Could not enable any direct solver:\n"
115 << (triedEpetra_ ? "Epetra mode was disabled due to an error:\n" : "")
116 << (triedEpetra_ ? errorEpetra_ : "")
117 << (triedTpetra_ ? "Tpetra mode was disabled due to an error:\n" : "")
118 << (triedTpetra_ ? errorTpetra_ : "")
119 << (triedBelos_ ? "Belos was disabled due to an error:\n" : "")
120 << (triedBelos_ ? errorBelos_ : "")
121 << (triedStratimikos_ ? "Stratimikos was disabled due to an error:\n" : "")
123 << (triedRefMaxwell_ ? "RefMaxwell was disabled due to an error:\n" : "")
125 ;
126
127 this->SetParameterList(paramList);
128}
129
130template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
131void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::SetFactory(const std::string& varName, const RCP<const FactoryBase>& factory) {
132 // We need to propagate SetFactory to proper place
133 if (!sEpetra_.is_null()) sEpetra_->SetFactory(varName, factory);
134 if (!sTpetra_.is_null()) sTpetra_->SetFactory(varName, factory);
135 if (!sBelos_.is_null()) sBelos_->SetFactory(varName, factory);
136 if (!sStratimikos_.is_null()) sStratimikos_->SetFactory(varName, factory);
137 if (!sRefMaxwell_.is_null()) sRefMaxwell_->SetFactory(varName, factory);
138}
139
140template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
142 if (!sBelos_.is_null())
143 s_ = sBelos_;
144 else if (!sStratimikos_.is_null())
145 s_ = sStratimikos_;
146 else if (!sRefMaxwell_.is_null())
147 s_ = sRefMaxwell_;
148 else {
149 // Decide whether we are running in Epetra or Tpetra mode
150 //
151 // Theoretically, we could make this decision in the constructor, and create only
152 // one of the smoothers. But we want to be able to reuse, so one can imagine a scenario
153 // where one first runs hierarchy with tpetra matrix, and then with epetra.
154 bool useTpetra = (currentLevel.lib() == Xpetra::UseTpetra);
155 s_ = (useTpetra ? sTpetra_ : sEpetra_);
156 if (s_.is_null()) {
157 if (useTpetra) {
158#if not defined(HAVE_MUELU_AMESOS2)
159 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
160 "Error: running in Tpetra mode, but MueLu with Amesos2 was disabled during the configure stage.\n"
161 "Please make sure that:\n"
162 " - Amesos2 is enabled (Trilinos_ENABLE_Amesos2=ON),\n"
163 " - Amesos2 is available for MueLu to use (MueLu_ENABLE_Amesos2=ON)\n");
164#else
165 if (triedTpetra_)
166 this->GetOStream(Errors) << "Tpetra mode was disabled due to an error:\n"
167 << errorTpetra_ << std::endl;
168#endif
169 }
170 if (!useTpetra) {
171#if not defined(HAVE_MUELU_AMESOS)
172 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
173 "Error: running in Epetra mode, but MueLu with Amesos was disabled during the configure stage.\n"
174 "Please make sure that:\n"
175 " - Amesos is enabled (you can do that with Trilinos_ENABLE_Amesos=ON),\n"
176 " - Amesos is available for MueLu to use (MueLu_ENABLE_Amesos=ON)\n");
177#else
178 if (triedEpetra_)
179 this->GetOStream(Errors) << "Epetra mode was disabled due to an error:\n"
180 << errorEpetra_ << std::endl;
181#endif
182 }
183 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
184 "Direct solver for " << (useTpetra ? "Tpetra" : "Epetra") << " was not constructed");
185 }
186 }
187
188 s_->DeclareInput(currentLevel);
189}
190
191template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
193 if (SmootherPrototype::IsSetup() == true)
194 this->GetOStream(Warnings0) << "MueLu::DirectSolver::Setup(): Setup() has already been called" << std::endl;
195
196 int oldRank = s_->SetProcRankVerbose(this->GetProcRankVerbose());
197
198 s_->Setup(currentLevel);
199
200 s_->SetProcRankVerbose(oldRank);
201
203
204 this->SetParameterList(s_->GetParameterList());
205}
206
207template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
208void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
209 TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::AmesosSmoother::Apply(): Setup() has not been called");
210
211 s_->Apply(X, B, InitialGuessIsZero);
212}
213
214template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
215RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> > DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Copy() const {
216 RCP<DirectSolver> newSmoo = rcp(new DirectSolver(*this));
217
218 // We need to be quite careful with Copy
219 // We still want DirectSolver to follow Prototype Pattern, so we need to hide the fact that we do have some state
220 if (!sEpetra_.is_null())
221 newSmoo->sEpetra_ = sEpetra_->Copy();
222 if (!sTpetra_.is_null())
223 newSmoo->sTpetra_ = sTpetra_->Copy();
224 if (!sBelos_.is_null())
225 newSmoo->sBelos_ = sBelos_->Copy();
226 if (!sStratimikos_.is_null())
227 newSmoo->sStratimikos_ = sStratimikos_->Copy();
228 if (!sRefMaxwell_.is_null())
229 newSmoo->sRefMaxwell_ = sRefMaxwell_->Copy();
230
231 // Copy the default mode
232 if (s_.get() == sBelos_.get())
233 newSmoo->s_ = newSmoo->sBelos_;
234 else if (s_.get() == sStratimikos_.get())
235 newSmoo->s_ = newSmoo->sStratimikos_;
236 else if (s_.get() == sRefMaxwell_.get())
237 newSmoo->s_ = newSmoo->sRefMaxwell_;
238 else if (s_.get() == sTpetra_.get())
239 newSmoo->s_ = newSmoo->sTpetra_;
240 else
241 newSmoo->s_ = newSmoo->sEpetra_;
242 newSmoo->SetParameterList(this->GetParameterList());
243
244 return newSmoo;
245}
246
247template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
249 std::ostringstream out;
250 if (s_ != Teuchos::null) {
251 out << s_->description();
252 } else {
254 out << "{type = " << type_ << "}";
255 }
256 return out.str();
257}
258
259template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
260void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream& out, const VerbLevel verbLevel) const {
262
263 if (verbLevel & Parameters0)
264 out0 << "Prec. type: " << type_ << std::endl;
265
266 if (verbLevel & Parameters1) {
267 out0 << "Parameter list: " << std::endl;
268 Teuchos::OSTab tab3(out);
269 out << this->GetParameterList();
270 }
271
272 if (verbLevel & Debug)
273 out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
274}
275
276} // namespace MueLu
277
278#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)