MueLu  Version of the Day
MueLu_TrilinosSmoother_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_TRILINOSSMOOTHER_DEF_HPP
47 #define MUELU_TRILINOSSMOOTHER_DEF_HPP
48 
49 #include <Xpetra_Map.hpp>
50 #include <Xpetra_Matrix.hpp>
51 
53 
54 #include "MueLu_Level.hpp"
55 #include "MueLu_IfpackSmoother.hpp"
56 #include "MueLu_Ifpack2Smoother.hpp"
57 #include "MueLu_Exceptions.hpp"
58 
59 namespace MueLu {
60 
61  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
62  TrilinosSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::TrilinosSmoother(const std::string& type, const Teuchos::ParameterList& paramListIn, const LO& overlap)
63  : type_(type), overlap_(overlap)
64  {
65  // The original idea behind all smoothers was to use prototype pattern. However, it does not fully work of the dependencies
66  // calculation. Particularly, we need to propagate DeclareInput to proper prototypes. Therefore, both TrilinosSmoother and
67  // DirectSolver do not follow the pattern exactly.
68  // The difference is that in order to propagate the calculation of dependencies, we need to call a DeclareInput on a
69  // constructed object (or objects, as we have two different code branches for Epetra and Tpetra). The only place where we
70  // could construct these objects is the constructor. Thus, we need to store RCPs, and both TrilinosSmoother and DirectSolver
71  // obtain a state: they contain RCP to smoother prototypes.
72  sEpetra_ = Teuchos::null;
73  sTpetra_ = Teuchos::null;
74 
75  TEUCHOS_TEST_FOR_EXCEPTION(overlap_ < 0, Exceptions::RuntimeError, "Overlap parameter is negative (" << overlap << ")");
76 
77  // paramList contains only parameters which are understood by Ifpack/Ifpack2
78  ParameterList paramList = paramListIn;
79 
80 
81  // We want TrilinosSmoother to be able to work with both Epetra and Tpetra objects, therefore we try to construct both
82  // Ifpack and Ifpack2 smoother prototypes. The construction really depends on configuration options.
83  triedEpetra_ = triedTpetra_ = false;
84 #if defined(HAVE_MUELU_TPETRA) && defined(HAVE_MUELU_IFPACK2)
85  try {
86  sTpetra_ = rcp(new Ifpack2Smoother(type_, paramList, overlap_));
87  if (sTpetra_.is_null())
88  errorTpetra_ = "Unable to construct Ifpack2 smoother";
89  } catch (Exceptions::RuntimeError& e) {
90  errorTpetra_ = e.what();
91  } catch (Exceptions::BadCast& e) {
92  errorTpetra_ = e.what();
93  }
94  triedTpetra_ = true;
95 #endif
96 #if defined(HAVE_MUELU_EPETRA) && defined(HAVE_MUELU_IFPACK)
97  try {
98  // GetIfpackSmoother masks the template argument matching, and simply throws if template arguments are incompatible with Epetra
100  if (sEpetra_.is_null())
101  errorEpetra_ = "Unable to construct Ifpack smoother";
102  } catch (Exceptions::RuntimeError& e) {
103  // IfpackSmoother throws if Scalar != double, LocalOrdinal != int, GlobalOrdinal != int
104  errorEpetra_ = e.what();
105  }
106  triedEpetra_ = true;
107 #endif
108 
109  // Check if we were able to construct at least one smoother. In many cases that's all we need, for instance if a user
110  // simply wants to use Tpetra only stack, never enables Ifpack, and always runs Tpetra objects.
111  TEUCHOS_TEST_FOR_EXCEPTION(!triedEpetra_ && !triedTpetra_, Exceptions::RuntimeError, "Unable to construct any smoother."
112  "Please enable (TPETRA and IFPACK2) or (EPETRA and IFPACK)");
113 
114  TEUCHOS_TEST_FOR_EXCEPTION(sEpetra_.is_null() && sTpetra_.is_null(), Exceptions::RuntimeError,
115  "Could not construct any smoother:\n"
116  << (triedEpetra_ ? "=> Failed to build an Epetra smoother due to the following exception:\n" : "=> Epetra and/or Ifpack are not enabled.\n")
117  << (triedEpetra_ ? errorEpetra_ + "\n" : "")
118  << (triedTpetra_ ? "=> Failed to build a Tpetra smoother due to the following exception:\n" : "=> Tpetra and/or Ifpack2 are not enabled.\n")
119  << (triedTpetra_ ? errorTpetra_ + "\n" : ""));
120 
121  this->SetParameterList(paramList);
122  }
123 
124  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
125  void TrilinosSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::SetFactory(const std::string& varName, const RCP<const FactoryBase>& factory) {
126  // We need to propagate SetFactory to proper place
127  if (!sEpetra_.is_null()) sEpetra_->SetFactory(varName, factory);
128  if (!sTpetra_.is_null()) sTpetra_->SetFactory(varName, factory);
129  }
130 
131  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
133  // Decide whether we are running in Epetra or Tpetra mode
134  //
135  // Theoretically, we could make this decision in the constructor, and create only
136  // one of the smoothers. But we want to be able to reuse, so one can imagine a scenario
137  // where one first runs hierarchy with tpetra matrix, and then with epetra.
138  bool useTpetra = (currentLevel.lib() == Xpetra::UseTpetra);
139  s_ = (useTpetra ? sTpetra_ : sEpetra_);
140  if (s_.is_null()) {
141  if (useTpetra) {
142 #if not defined(HAVE_MUELU_IFPACK22)
143  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
144  "Error: running in Tpetra mode, but MueLu with Ifpack2 was disabled during the configure stage.\n"
145  "Please make sure that:\n"
146  " - Ifpack2 is enabled (Trilinos_ENABLE_Ifpack2=ON),\n"
147  " - Ifpack2 is available for MueLu to use (MueLu_ENABLE_Ifpack2=ON)\n");
148 #else
149  if (triedTpetra_)
150  this->GetOStream(Errors) << "Tpetra mode was disabled due to an error:\n" << errorTpetra_ << std::endl;
151 #endif
152  }
153  if (!useTpetra) {
154 #if not defined(HAVE_MUELU_IFPACK)
155  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
156  "Error: running in Epetra mode, but MueLu with Ifpack was disabled during the configure stage.\n"
157  "Please make sure that:\n"
158  " - Ifpack is enabled (you can do that with Trilinos_ENABLE_Ifpack=ON),\n"
159  " - Ifpack is available for MueLu to use (MueLu_ENABLE_Ifpack=ON)\n");
160 #else
161  if (triedEpetra_)
162  this->GetOStream(Errors) << "Epetra mode was disabled due to an error:\n" << errorEpetra_ << std::endl;
163 #endif
164  }
165  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError,
166  "Smoother for " << (useTpetra ? "Tpetra" : "Epetra") << " was not constructed");
167  }
168 
169  s_->DeclareInput(currentLevel);
170  }
171 
172  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
174  if (SmootherPrototype::IsSetup() == true)
175  this->GetOStream(Warnings0) << "MueLu::TrilinosSmoother::Setup(): Setup() has already been called" << std::endl;
176 
177  int oldRank = s_->SetProcRankVerbose(this->GetProcRankVerbose());
178 
179  s_->Setup(currentLevel);
180 
181  s_->SetProcRankVerbose(oldRank);
182 
184 
185  this->SetParameterList(s_->GetParameterList());
186  }
187 
188  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
189  void TrilinosSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool InitialGuessIsZero) const {
190  TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::TrilinosSmoother::Apply(): Setup() has not been called");
191 
192  s_->Apply(X, B, InitialGuessIsZero);
193  }
194 
195  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
196  RCP<MueLu::SmootherPrototype<Scalar, LocalOrdinal, GlobalOrdinal, Node> >
198  RCP<TrilinosSmoother> newSmoo = rcp(new TrilinosSmoother(type_, this->GetParameterList(), overlap_));
199 
200  // We need to be quite careful with Copy
201  // We still want TrilinosSmoother to follow Prototype Pattern, so we need to hide the fact that we do have some state
202  if (!sEpetra_.is_null())
203  newSmoo->sEpetra_ = sEpetra_->Copy();
204  if (!sTpetra_.is_null())
205  newSmoo->sTpetra_ = sTpetra_->Copy();
206 
207  // Copy the default mode
208  newSmoo->s_ = (s_.get() == sTpetra_.get() ? newSmoo->sTpetra_ : newSmoo->sEpetra_);
209  newSmoo->SetParameterList(this->GetParameterList());
210 
211  return newSmoo;
212  }
213 
214  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
216  if (type == "RELAXATION") { return "point relaxation stand-alone"; }
217  if (type == "CHEBYSHEV") { return "Chebyshev"; }
218  if (type == "ILUT") { return "ILUT"; }
219  if (type == "RILUK") { return "ILU"; }
220  if (type == "ILU") { return "ILU"; }
221  if (type == "Amesos") { return "Amesos"; }
222 
223  // special types
224 
225  // Note: for Ifpack there is no distinction between block and banded relaxation as there is no
226  // BandedContainer or TridiagonalContainer.
227  if (type == "LINESMOOTHING_BLOCKRELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
228  if (type == "LINESMOOTHING_BLOCK RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
229  if (type == "LINESMOOTHING_BLOCK_RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
230  if (type == "LINESMOOTHING_BANDEDRELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
231  if (type == "LINESMOOTHING_BANDED RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
232  if (type == "LINESMOOTHING_BANDED_RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
233  if (type == "LINESMOOTHING_TRIDIRELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
234  if (type == "LINESMOOTHING_TRIDI RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
235  if (type == "LINESMOOTHING_TRIDI_RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
236  if (type == "LINESMOOTHING_TRIDIAGONALRELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
237  if (type == "LINESMOOTHING_TRIDIAGONAL RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
238  if (type == "LINESMOOTHING_TRIDIAGONAL_RELAXATION") { return "LINESMOOTHING_BLOCKRELAXATION"; }
239  if(type == "BLOCK_RELAXATION" ||
240  type == "BLOCK RELAXATION" ||
241  type == "BLOCKRELAXATION" ||
242  // Banded
243  type == "BANDED_RELAXATION" ||
244  type == "BANDED RELAXATION" ||
245  type == "BANDEDRELAXATION" ||
246  // Tridiagonal
247  type == "TRIDI_RELAXATION" ||
248  type == "TRIDI RELAXATION" ||
249  type == "TRIDIRELAXATION" ||
250  type == "TRIDIAGONAL_RELAXATION" ||
251  type == "TRIDIAGONAL RELAXATION" ||
252  type == "TRIDIAGONALRELAXATION") {
253  return "block relaxation stand-alone";
254  }
255 
256  TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Cannot convert Ifpack2 preconditioner name to Ifpack: unknown type: \"" + type + "\"");
257  }
258 
259  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
260  Teuchos::ParameterList TrilinosSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Ifpack2ToIfpack1Param(const Teuchos::ParameterList& ifpack2List) {
261  Teuchos::ParameterList ifpack1List = ifpack2List;
262 
263  if (ifpack2List.isParameter("relaxation: type") && ifpack2List.get<std::string>("relaxation: type") == "Symmetric Gauss-Seidel")
264  ifpack1List.set("relaxation: type", "symmetric Gauss-Seidel");
265 
266  if (ifpack2List.isParameter("fact: iluk level-of-fill")) {
267  ifpack1List.remove("fact: iluk level-of-fill");
268  ifpack1List.set("fact: level-of-fill", ifpack2List.get<int>("fact: iluk level-of-fill"));
269  }
270 
271  return ifpack1List;
272  }
273 
274  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
276  std::ostringstream out;
277  if (s_ != Teuchos::null) {
278  out << s_->description();
279  } else {
281  out << "{type = " << type_ << "}";
282  }
283  return out.str();
284  }
285 
286  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
287  void TrilinosSmoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(Teuchos::FancyOStream& out, const VerbLevel verbLevel) const {
289 
290  if (verbLevel & Parameters0)
291  out0 << "Prec. type: " << type_ << std::endl;
292 
293  if (verbLevel & Parameters1) {
294  out0 << "PrecType: " << type_ << std::endl;
295  out0 << "Parameter list: " << std::endl;
296  Teuchos::OSTab tab2(out);
297  out << this->GetParameterList();
298  out0 << "Overlap: " << overlap_ << std::endl;
299  }
300 
301  if (verbLevel & Debug) {
302  out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl
303  << "-" << std::endl
304  << "Epetra PrecType: " << Ifpack2ToIfpack1Type(type_) << std::endl
305  << "Epetra Parameter list: " << std::endl;
306  Teuchos::OSTab tab2(out);
307  out << Ifpack2ToIfpack1Param(this->GetParameterList());;
308  }
309  }
310 
311 } // namespace MueLu
312 
313 #endif // MUELU_TRILINOSSMOOTHER_DEF_HPP
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
virtual std::string description() const
Return a simple one-line description of this object.
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
Class that encapsulates Ifpack2 smoothers.
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Xpetra::UnderlyingLib lib()
virtual void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
bool IsSetup() const
Get the state of a smoother prototype.
Class that encapsulates external library smoothers.
RCP< SmootherPrototype > Copy() const
When this prototype is cloned using Copy(), the clone is an Ifpack or an Ifpack2 smoother.
void Setup(Level &currentLevel)
TrilinosSmoother cannot be turned into a smoother using Setup(). Setup() always returns a RuntimeErro...
LO overlap_
overlap when using the smoother in additive Schwarz mode
static Teuchos::ParameterList Ifpack2ToIfpack1Param(const Teuchos::ParameterList &ifpack2List)
Convert an Ifpack2 parameter list to Ifpack.
static std::string Ifpack2ToIfpack1Type(const std::string &type)
Convert an Ifpack2 preconditioner name to Ifpack.
std::string type_
ifpack1/2-specific key phrase that denote smoother type
friend class TrilinosSmoother
Friend declaration required for clone() functionality.
void DeclareInput(Level &currentLevel) const
Input.
RCP< SmootherPrototype > sEpetra_
Smoother.
void SetFactory(const std::string &varName, const RCP< const FactoryBase > &factory)
Custom SetFactory.
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
TrilinosSmoother cannot be applied. Apply() always returns a RuntimeError exception.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level to an FancyOStream object.
std::string description() const
Return a simple one-line description of this object.
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line)
@ Debug
Print additional debugging information.
@ Errors
Errors.
@ Parameters0
Print class parameters.
@ Parameters1
Print class parameters (more parameters, more verbose)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.