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 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 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
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_DIRECTSOLVER_DEF_HPP
47 #define MUELU_DIRECTSOLVER_DEF_HPP
48 
49 #include <Xpetra_Utils.hpp>
50 #include <Xpetra_Matrix.hpp>
51 
53 
54 #include "MueLu_Exceptions.hpp"
55 #include "MueLu_Level.hpp"
56 
57 #include "MueLu_Amesos2Smoother.hpp"
58 #include "MueLu_AmesosSmoother.hpp"
59 #include "MueLu_BelosSmoother.hpp"
60 #include "MueLu_StratimikosSmoother.hpp"
61 #include "MueLu_RefMaxwellSmoother.hpp"
62 
63 namespace MueLu {
64 
65 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
67  : type_(type) {
68  // The original idea behind all smoothers was to use prototype pattern. However, it does not fully work of the dependencies
69  // calculation. Particularly, we need to propagate DeclareInput to proper prototypes. Therefore, both TrilinosSmoother and
70  // DirectSolver do not follow the pattern exactly.
71  // The difference is that in order to propagate the calculation of dependencies, we need to call a DeclareInput on a
72  // constructed object (or objects, as we have two different code branches for Epetra and Tpetra). The only place where we
73  // could construct these objects is the constructor. Thus, we need to store RCPs, and both TrilinosSmoother and DirectSolver
74  // obtain a state: they contain RCP to smoother prototypes.
75  sEpetra_ = Teuchos::null;
76  sTpetra_ = Teuchos::null;
77  sBelos_ = Teuchos::null;
78 
79  ParameterList paramList = paramListIn;
80 
81  // We want DirectSolver to be able to work with both Epetra and Tpetra objects, therefore we try to construct both
82  // Amesos and Amesos2 solver prototypes. The construction really depends on configuration options.
83  triedEpetra_ = triedTpetra_ = false;
84 #if defined(HAVE_MUELU_AMESOS2)
85  try {
86  sTpetra_ = rcp(new Amesos2Smoother(type_, paramList));
87  if (sTpetra_.is_null())
88  errorTpetra_ = "Unable to construct Amesos2 direct solver";
89  else if (!sTpetra_->constructionSuccessful()) {
90  errorTpetra_ = sTpetra_->constructionErrorMsg();
91  sTpetra_ = Teuchos::null;
92  }
93  } catch (Exceptions::RuntimeError& e) {
94  errorTpetra_ = e.what();
95  } catch (Exceptions::BadCast& e) {
96  errorTpetra_ = e.what();
98  errorTpetra_ = e.what();
99  }
100  triedTpetra_ = true;
101 #endif
102 #if defined(HAVE_MUELU_EPETRA) && defined(HAVE_MUELU_AMESOS)
103  try {
104  // GetAmesosSmoother masks the template argument matching, and simply throws if template arguments are incompatible with Epetra
105  sEpetra_ = GetAmesosSmoother<SC, LO, GO, NO>(type_, paramList);
106  if (sEpetra_.is_null())
107  errorEpetra_ = "Unable to construct Amesos direct solver";
108  else if (!sEpetra_->constructionSuccessful()) {
109  errorEpetra_ = sEpetra_->constructionErrorMsg();
110  sEpetra_ = Teuchos::null;
111  }
112  } catch (Exceptions::RuntimeError& e) {
113  // AmesosSmoother throws if Scalar != double, LocalOrdinal != int, GlobalOrdinal != int
114  errorEpetra_ = e.what();
115  }
116  triedEpetra_ = true;
117 #endif
118 #if defined(HAVE_MUELU_BELOS)
119  try {
120  sBelos_ = rcp(new BelosSmoother(type_, paramList));
121  if (sBelos_.is_null())
122  errorBelos_ = "Unable to construct Belos solver";
123  else if (!sBelos_->constructionSuccessful()) {
124  errorBelos_ = sBelos_->constructionErrorMsg();
125  sBelos_ = Teuchos::null;
126  }
127  } catch (Exceptions::RuntimeError& e) {
128  errorBelos_ = e.what();
129  } catch (Exceptions::BadCast& e) {
130  errorBelos_ = e.what();
131  }
132  triedBelos_ = true;
133 #endif
134 #if defined(HAVE_MUELU_STRATIMIKOS) && defined(HAVE_MUELU_THYRA)
135  try {
136  sStratimikos_ = rcp(new StratimikosSmoother(type_, paramList));
137  if (sStratimikos_.is_null())
138  errorStratimikos_ = "Unable to construct Stratimikos smoother";
139  else if (!sStratimikos_->constructionSuccessful()) {
140  errorStratimikos_ = sStratimikos_->constructionErrorMsg();
141  sStratimikos_ = Teuchos::null;
142  }
143  } catch (Exceptions::RuntimeError& e) {
144  errorStratimikos_ = e.what();
145  }
146  triedStratimikos_ = true;
147 #endif
148  try {
149  sRefMaxwell_ = rcp(new RefMaxwellSmoother(type_, paramList));
150  if (sRefMaxwell_.is_null())
151  errorRefMaxwell_ = "Unable to construct RefMaxwell smoother";
152  else if (!sRefMaxwell_->constructionSuccessful()) {
153  errorRefMaxwell_ = sRefMaxwell_->constructionErrorMsg();
154  sRefMaxwell_ = Teuchos::null;
155  }
156  } catch (Exceptions::RuntimeError& e) {
157  errorRefMaxwell_ = e.what();
158  }
159  triedRefMaxwell_ = true;
160 
161  // Check if we were able to construct at least one solver. In many cases that's all we need, for instance if a user
162  // simply wants to use Tpetra only stack, never enables Amesos, and always runs Tpetra objects.
164  "Unable to construct any direct solver."
165  "Plase enable (TPETRA and AMESOS2) or (EPETRA and AMESOS) or (BELOS) or (STRATIMIKOS)");
166 
167  TEUCHOS_TEST_FOR_EXCEPTION(sEpetra_.is_null() && sTpetra_.is_null() && sBelos_.is_null() && sStratimikos_.is_null() && sRefMaxwell_.is_null(), Exceptions::RuntimeError,
168  "Could not enable any direct solver:\n"
169  << (triedEpetra_ ? "Epetra mode was disabled due to an error:\n" : "")
170  << (triedEpetra_ ? errorEpetra_ : "")
171  << (triedTpetra_ ? "Tpetra mode was disabled due to an error:\n" : "")
172  << (triedTpetra_ ? errorTpetra_ : "")
173  << (triedBelos_ ? "Belos was disabled due to an error:\n" : "")
174  << (triedBelos_ ? errorBelos_ : "")
175  << (triedStratimikos_ ? "Stratimikos was disabled due to an error:\n" : "")
177  << (triedRefMaxwell_ ? "RefMaxwell was disabled due to an error:\n" : "")
178  << (triedRefMaxwell_ ? errorRefMaxwell_ : ""));
179  ;
180 
181  this->SetParameterList(paramList);
182 }
183 
184 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
186  // We need to propagate SetFactory to proper place
187  if (!sEpetra_.is_null()) sEpetra_->SetFactory(varName, factory);
188  if (!sTpetra_.is_null()) sTpetra_->SetFactory(varName, factory);
189  if (!sBelos_.is_null()) sBelos_->SetFactory(varName, factory);
190  if (!sStratimikos_.is_null()) sStratimikos_->SetFactory(varName, factory);
191  if (!sRefMaxwell_.is_null()) sRefMaxwell_->SetFactory(varName, factory);
192 }
193 
194 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
196  if (!sBelos_.is_null())
197  s_ = sBelos_;
198  else if (!sStratimikos_.is_null())
199  s_ = sStratimikos_;
200  else if (!sRefMaxwell_.is_null())
201  s_ = sRefMaxwell_;
202  else {
203  // Decide whether we are running in Epetra or Tpetra mode
204  //
205  // Theoretically, we could make this decision in the constructor, and create only
206  // one of the smoothers. But we want to be able to reuse, so one can imagine a scenario
207  // where one first runs hierarchy with tpetra matrix, and then with epetra.
208  bool useTpetra = (currentLevel.lib() == Xpetra::UseTpetra);
209  s_ = (useTpetra ? sTpetra_ : sEpetra_);
210  if (s_.is_null()) {
211  if (useTpetra) {
212 #if not defined(HAVE_MUELU_AMESOS2)
214  "Error: running in Tpetra mode, but MueLu with Amesos2 was disabled during the configure stage.\n"
215  "Please make sure that:\n"
216  " - Amesos2 is enabled (Trilinos_ENABLE_Amesos2=ON),\n"
217  " - Amesos2 is available for MueLu to use (MueLu_ENABLE_Amesos2=ON)\n");
218 #else
219  if (triedTpetra_)
220  this->GetOStream(Errors) << "Tpetra mode was disabled due to an error:\n"
221  << errorTpetra_ << std::endl;
222 #endif
223  }
224  if (!useTpetra) {
225 #if not defined(HAVE_MUELU_AMESOS)
227  "Error: running in Epetra mode, but MueLu with Amesos was disabled during the configure stage.\n"
228  "Please make sure that:\n"
229  " - Amesos is enabled (you can do that with Trilinos_ENABLE_Amesos=ON),\n"
230  " - Amesos is available for MueLu to use (MueLu_ENABLE_Amesos=ON)\n");
231 #else
232  if (triedEpetra_)
233  this->GetOStream(Errors) << "Epetra mode was disabled due to an error:\n"
234  << errorEpetra_ << std::endl;
235 #endif
236  }
238  "Direct solver for " << (useTpetra ? "Tpetra" : "Epetra") << " was not constructed");
239  }
240  }
241 
242  s_->DeclareInput(currentLevel);
243 }
244 
245 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
247  if (SmootherPrototype::IsSetup() == true)
248  this->GetOStream(Warnings0) << "MueLu::DirectSolver::Setup(): Setup() has already been called" << std::endl;
249 
250  int oldRank = s_->SetProcRankVerbose(this->GetProcRankVerbose());
251 
252  s_->Setup(currentLevel);
253 
254  s_->SetProcRankVerbose(oldRank);
255 
257 
258  this->SetParameterList(s_->GetParameterList());
259 }
260 
261 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
262 void DirectSolver<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
263  TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::AmesosSmoother::Apply(): Setup() has not been called");
264 
265  s_->Apply(X, B, InitialGuessIsZero);
266 }
267 
268 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
270  RCP<DirectSolver> newSmoo = rcp(new DirectSolver(*this));
271 
272  // We need to be quite careful with Copy
273  // We still want DirectSolver to follow Prototype Pattern, so we need to hide the fact that we do have some state
274  if (!sEpetra_.is_null())
275  newSmoo->sEpetra_ = sEpetra_->Copy();
276  if (!sTpetra_.is_null())
277  newSmoo->sTpetra_ = sTpetra_->Copy();
278  if (!sBelos_.is_null())
279  newSmoo->sBelos_ = sBelos_->Copy();
280  if (!sStratimikos_.is_null())
281  newSmoo->sStratimikos_ = sStratimikos_->Copy();
282  if (!sRefMaxwell_.is_null())
283  newSmoo->sRefMaxwell_ = sRefMaxwell_->Copy();
284 
285  // Copy the default mode
286  if (s_.get() == sBelos_.get())
287  newSmoo->s_ = newSmoo->sBelos_;
288  else if (s_.get() == sStratimikos_.get())
289  newSmoo->s_ = newSmoo->sStratimikos_;
290  else if (s_.get() == sRefMaxwell_.get())
291  newSmoo->s_ = newSmoo->sRefMaxwell_;
292  else if (s_.get() == sTpetra_.get())
293  newSmoo->s_ = newSmoo->sTpetra_;
294  else
295  newSmoo->s_ = newSmoo->sEpetra_;
296  newSmoo->SetParameterList(this->GetParameterList());
297 
298  return newSmoo;
299 }
300 
301 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
303  std::ostringstream out;
304  if (s_ != Teuchos::null) {
305  out << s_->description();
306  } else {
308  out << "{type = " << type_ << "}";
309  }
310  return out.str();
311 }
312 
313 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
316 
317  if (verbLevel & Parameters0)
318  out0 << "Prec. type: " << type_ << std::endl;
319 
320  if (verbLevel & Parameters1) {
321  out0 << "Parameter list: " << std::endl;
322  Teuchos::OSTab tab3(out);
323  out << this->GetParameterList();
324  }
325 
326  if (verbLevel & Debug)
327  out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl;
328 }
329 
330 } // namespace MueLu
331 
332 #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:99
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)