MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_SmootherFactory_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_SMOOTHERFACTORY_DEF_HPP
11 #define MUELU_SMOOTHERFACTORY_DEF_HPP
12 
14 
15 #include "MueLu_Level.hpp"
16 #include "MueLu_Exceptions.hpp"
17 #include "MueLu_SmootherPrototype.hpp"
18 
19 namespace MueLu {
20 
21 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
23 
24 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
26  SetSmootherPrototypes(preAndPostSmootherPrototype);
27 }
28 
29 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
31  RCP<SmootherPrototype> postSmootherPrototype) {
32  SetSmootherPrototypes(preSmootherPrototype, postSmootherPrototype);
33 }
34 
35 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
37  preSmootherPrototype_ = postSmootherPrototype_ = preAndPostSmootherPrototype;
38  CheckPrototypes();
39 }
40 
41 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
43  RCP<SmootherPrototype> postSmootherPrototype) {
44  preSmootherPrototype_ = preSmootherPrototype;
45  postSmootherPrototype_ = postSmootherPrototype;
46  CheckPrototypes();
47 }
48 
49 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
51  RCP<ParameterList> validParamList = rcp(new ParameterList());
52 
53  validParamList->set<bool>("keep smoother data", false, "Keep constructed smoothers for later reuse");
54 
55  validParamList->set<RCP<SmootherPrototype> >("PreSmoother data", null, "Pre-smoother data for reuse");
56  validParamList->set<RCP<SmootherPrototype> >("PostSmoother data", null, "Post-smoother data for reuse");
57 
58  return validParamList;
59 }
60 
61 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
63  TEUCHOS_TEST_FOR_EXCEPTION(preSmootherPrototype_ != Teuchos::null && preSmootherPrototype_->IsSetup() == true,
64  Exceptions::RuntimeError, "preSmoother prototype is not a smoother prototype (IsSetup() == true)");
65  TEUCHOS_TEST_FOR_EXCEPTION(postSmootherPrototype_ != Teuchos::null && postSmootherPrototype_->IsSetup() == true,
66  Exceptions::RuntimeError, "postSmoother prototype is not a smoother prototype (IsSetup() == true)");
67 }
68 
69 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
71  RCP<SmootherPrototype>& postSmootherPrototype) const {
72  preSmootherPrototype = preSmootherPrototype_;
73  postSmootherPrototype = postSmootherPrototype_;
74 }
75 
76 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
78  if (preSmootherPrototype_ != Teuchos::null)
79  preSmootherPrototype_->DeclareInput(currentLevel);
80 
81  if ((postSmootherPrototype_ != Teuchos::null) && (preSmootherPrototype_ != postSmootherPrototype_))
82  postSmootherPrototype_->DeclareInput(currentLevel);
83 }
84 
85 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
87  return BuildSmoother(currentLevel, BOTH);
88 }
89 
90 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
92  // SmootherFactory is quite tricky because of the fact that one of the smoother prototypes may be zero.
93  // The challenge is that we have no way of knowing how user uses this factory. For instance, lets say
94  // user wants to use s1 prototype as a presmoother, and s2 as a postsmoother. They could do:
95  // (a) create SmootherFactory(s1, s2), or
96  // (b) create SmootherFactory(s1, null) and SmootherFactory(null, s2)
97  // It may also happen that somewhere somebody set presmoother factory = postsmoother factory = (a)
98  // How do you do DeclareInput in this case? It could easily introduce a bug if a user does not check
99  // whether presmoother = postsmoother. A buggy code could look like that:
100  // RCP<SmootherFactory> s = rcp(new SmootherFactory(s1,s2));
101  // level.Request("PreSmoother", s.get());
102  // level.Request("PostSmoother", s.get());
103  // Get<RCP<SmootherBase> > pre = Get<RCP<SmootherBase> >("PreSmoother", s.get());
104  // Get<RCP<SmootherBase> > post = Get<RCP<SmootherBase> >("PostSmoother", s.get());
105  // This code would call DeclareInput in request mode twice, but as the Build method generates both Pre and Post
106  // smoothers, it would call DelcareInput in release mode only once, leaving requests.
107  // This code has another problem if s2 = Teuchos::null. In that case, despite the request for PostSmoother, the factory
108  // would not generate one, and second Get would throw. The real issue here is that given a Factory pointer
109  // there is no way to be sure that this factory would generate any of "PreSmoother" or "PostSmoother", unless you are
110  // able to cast it to SmootherFactory, do GetPrototypes and to check whether any of those is Teuchos::null.
111 
112  const Teuchos::ParameterList& pL = GetParameterList();
113 
114  RCP<SmootherPrototype> preSmoother, postSmoother;
115  ParameterList preSmootherParams, postSmootherParams;
116 
117  if ((preOrPost & PRE) && !preSmootherPrototype_.is_null()) {
118  if (currentLevel.IsAvailable("PreSmoother data", this))
119  preSmoother = currentLevel.Get<RCP<SmootherPrototype> >("PreSmoother data", this);
120  else
121  preSmoother = preSmootherPrototype_->Copy();
122 
123  int oldRank = -1;
124  if (!currentLevel.GetComm().is_null())
125  oldRank = preSmoother->SetProcRankVerbose(currentLevel.GetComm()->getRank());
126 
127  preSmoother->Setup(currentLevel);
128  preSmootherParams = preSmoother->GetParameterList();
129 
130  if (oldRank != -1)
131  preSmoother->SetProcRankVerbose(oldRank);
132 
133  currentLevel.Set<RCP<SmootherBase> >("PreSmoother", preSmoother, this);
134 
135  if (pL.get<bool>("keep smoother data"))
136  Set(currentLevel, "PreSmoother data", preSmoother);
137  }
138 
139  if ((preOrPost & POST) && !postSmootherPrototype_.is_null()) {
140  if (preOrPost == BOTH && preSmootherPrototype_ == postSmootherPrototype_) {
141  // Simple reuse
142  // Same prototypes for pre- and post-smoothers mean that we only need to call Setup only once
143  postSmoother = preSmoother;
144 
145  // else if (preOrPost == BOTH &&
146  // preSmootherPrototype_ != Teuchos::null &&
147  // preSmootherPrototype_->GetType() == postSmootherPrototype_->GetType()) {
148 
149  // // More complex reuse case: need implementation of CopyParameters() and a smoothers smart enough to know when parameters affect the setup phase.
150 
151  // // YES: post-smoother == pre-smoother
152  // // => copy the pre-smoother to avoid the setup phase of the post-smoother.
153  // postSmoother = preSmoother->Copy();
154  // // If the post-smoother parameters are different from
155  // // pre-smoother, the parameters stored in the post-smoother
156  // // prototype are copied in the new post-smoother object.
157  // postSmoother->CopyParameters(postSmootherPrototype_);
158  // // If parameters don't influence the Setup phase (it is the case
159  // // for Jacobi, Chebyshev...), PostSmoother is already setup. Nothing
160  // // more to do. In the case of ILU, parameters of the smoother
161  // // are in fact the parameters of the Setup phase. The call to
162  // // CopyParameters resets the smoother (only if parameters are
163  // // different) and we must call Setup() again.
164  // postSmoother->Setup(currentLevel);
165  // }
166 
167  // // TODO: if CopyParameters do not exist, do setup twice.
168 
169  } else {
170  if (currentLevel.IsAvailable("PostSmoother data", this)) {
171  postSmoother = currentLevel.Get<RCP<SmootherPrototype> >("PostSmoother data", this);
172  } else {
173  // No reuse:
174  // - either we only do postsmoothing without any presmoothing
175  // - or our postsmoother is different from presmoother
176  postSmoother = postSmootherPrototype_->Copy();
177  }
178 
179  int oldRank = -1;
180  if (!currentLevel.GetComm().is_null())
181  oldRank = postSmoother->SetProcRankVerbose(GetProcRankVerbose());
182 
183  postSmoother->Setup(currentLevel);
184  postSmootherParams = postSmoother->GetParameterList();
185 
186  if (oldRank != -1)
187  postSmoother->SetProcRankVerbose(oldRank);
188  }
189 
190  currentLevel.Set<RCP<SmootherBase> >("PostSmoother", postSmoother, this);
191 
192  if (pL.get<bool>("keep smoother data"))
193  Set(currentLevel, "PostSmoother data", postSmoother);
194  }
195 
196  ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
197  if (postSmoother == preSmoother && !preSmoother.is_null()) {
198  paramList.sublist("smoother", false) = preSmoother->GetParameterList();
199 
200  } else {
201  if (!preSmoother.is_null())
202  paramList.sublist("presmoother", false) = preSmootherParams;
203 
204  if (!postSmoother.is_null())
205  paramList.sublist("postsmoother", false) = postSmootherParams;
206  }
207 
208 } // Build()
209 
210 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
212  std::ostringstream out;
214  std::string preStr = (preSmootherPrototype_ == Teuchos::null) ? "null" : preSmootherPrototype_->description();
215  std::string postStr = (preSmootherPrototype_ == postSmootherPrototype_) ? "pre" : ((postSmootherPrototype_ == Teuchos::null) ? "null" : postSmootherPrototype_->description());
216  out << "{pre = " << preStr << ", post = " << postStr << "}";
217  return out.str();
218 }
219 
220 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
223 
224  if (verbLevel & Parameters0) {
225  out0 << "PreSmoother : ";
226  if (preSmootherPrototype_.is_null()) {
227  out0 << "null" << std::endl;
228  } else {
229  Teuchos::OSTab tab2(out);
230  preSmootherPrototype_->describe(out, verbLevel);
231  }
232 
233  out0 << "PostSmoother: ";
234  if (postSmootherPrototype_ == preSmootherPrototype_) {
235  out0 << "same as PreSmoother" << std::endl;
236  } else if (postSmootherPrototype_ == Teuchos::null) {
237  out0 << "null" << std::endl;
238  } else {
239  Teuchos::OSTab tab2(out);
240  postSmootherPrototype_->describe(out, verbLevel);
241  out0 << "PostSmoother is different than PreSmoother (not the same object)" << std::endl;
242  }
243  }
244 
245  if (verbLevel & Debug) {
246  if (preSmootherPrototype_ != Teuchos::null || postSmootherPrototype_ != Teuchos::null) {
247  out0 << "-" << std::endl;
248  }
249  if (preSmootherPrototype_ != Teuchos::null) {
250  out0 << "RCP<preSmootherPrototype_> : " << preSmootherPrototype_ << std::endl;
251  }
252  if (postSmootherPrototype_ != Teuchos::null) {
253  out0 << "RCP<postSmootherPrototype_>: " << postSmootherPrototype_ << std::endl;
254  }
255  }
256 }
257 
258 } // namespace MueLu
259 
260 // TODO: doc: setup done twice if PostSmoother object != PreSmoother object and no adv. reused capability
261 
262 // TODO ReUse: If only one smoother is missing, SmootherFactory can be smart and build only the missing smoother.
263 // TODO (optim): we can also reuse if preOrPost = post and preSmoother available in Level
264 // we can also reuse if preOrPost = pre and postSmoother available in Level
265 
266 #endif // MUELU_SMOOTHERFACTORY_DEF_HPP
virtual const Teuchos::ParameterList & GetParameterList() const
SmootherFactory(RCP< SmootherPrototype > preAndPostSmootherPrototype=Teuchos::null)
Constructor.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access). Usage: Level-&gt;Get&lt; RCP&lt;Matrix&gt; &gt;(&quot;A&quot;, factory) if factory == NULL =&gt; use default factory.
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
RCP< const ParameterList > GetValidParameterList() const
Input.
virtual void Setup(Level &)=0
Print additional debugging information.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
void BuildSmoother(Level &currentLevel, const PreOrPost preOrPost=BOTH) const
void describe(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
void Build(Level &currentLevel) const
Creates pre and post smoothers.
virtual RCP< SmootherPrototype > Copy() const =0
void SetSmootherPrototypes(RCP< SmootherPrototype > preAndPostSmootherPrototype)
Set smoother prototypes.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
Print class parameters.
std::string description() const
Return a simple one-line description of this object.
int SetProcRankVerbose(int procRank) const
Set proc rank used for printing.
void GetSmootherPrototypes(RCP< SmootherPrototype > &preSmootherPrototype, RCP< SmootherPrototype > &postSmootherPrototype) const
Get smoother prototypes.
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
Exception throws to report errors in the internal logical of the program.
RCP< const Teuchos::Comm< int > > GetComm() const
virtual std::string description() const
Return a simple one-line description of this object.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need&#39;s value has been saved.
void DeclareInput(Level &currentLevel) const
Specifies the data that this class needs, and the factories that generate that data.
bool is_null() const