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 // ***********************************************************************
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_SMOOTHERFACTORY_DEF_HPP
47 #define MUELU_SMOOTHERFACTORY_DEF_HPP
48 
50 
51 #include "MueLu_Level.hpp"
52 #include "MueLu_Exceptions.hpp"
53 #include "MueLu_SmootherPrototype.hpp"
54 
55 namespace MueLu {
56 
57 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
59  SetSmootherPrototypes(preAndPostSmootherPrototype);
60 }
61 
62 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
64  RCP<SmootherPrototype> postSmootherPrototype) {
65  SetSmootherPrototypes(preSmootherPrototype, postSmootherPrototype);
66 }
67 
68 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
70  preSmootherPrototype_ = postSmootherPrototype_ = preAndPostSmootherPrototype;
71  CheckPrototypes();
72 }
73 
74 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
76  RCP<SmootherPrototype> postSmootherPrototype) {
77  preSmootherPrototype_ = preSmootherPrototype;
78  postSmootherPrototype_ = postSmootherPrototype;
79  CheckPrototypes();
80 }
81 
82 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
84  RCP<ParameterList> validParamList = rcp(new ParameterList());
85 
86  validParamList->set<bool>("keep smoother data", false, "Keep constructed smoothers for later reuse");
87 
88  validParamList->set<RCP<SmootherPrototype> >("PreSmoother data", null, "Pre-smoother data for reuse");
89  validParamList->set<RCP<SmootherPrototype> >("PostSmoother data", null, "Post-smoother data for reuse");
90 
91  return validParamList;
92 }
93 
94 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
96  TEUCHOS_TEST_FOR_EXCEPTION(preSmootherPrototype_ != Teuchos::null && preSmootherPrototype_->IsSetup() == true,
97  Exceptions::RuntimeError, "preSmoother prototype is not a smoother prototype (IsSetup() == true)");
98  TEUCHOS_TEST_FOR_EXCEPTION(postSmootherPrototype_ != Teuchos::null && postSmootherPrototype_->IsSetup() == true,
99  Exceptions::RuntimeError, "postSmoother prototype is not a smoother prototype (IsSetup() == true)");
100 }
101 
102 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
104  RCP<SmootherPrototype>& postSmootherPrototype) const {
105  preSmootherPrototype = preSmootherPrototype_;
106  postSmootherPrototype = postSmootherPrototype_;
107 }
108 
109 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
111  if (preSmootherPrototype_ != Teuchos::null)
112  preSmootherPrototype_->DeclareInput(currentLevel);
113 
114  if ((postSmootherPrototype_ != Teuchos::null) && (preSmootherPrototype_ != postSmootherPrototype_))
115  postSmootherPrototype_->DeclareInput(currentLevel);
116 }
117 
118 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
120  return BuildSmoother(currentLevel, BOTH);
121 }
122 
123 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
125  // SmootherFactory is quite tricky because of the fact that one of the smoother prototypes may be zero.
126  // The challenge is that we have no way of knowing how user uses this factory. For instance, lets say
127  // user wants to use s1 prototype as a presmoother, and s2 as a postsmoother. They could do:
128  // (a) create SmootherFactory(s1, s2), or
129  // (b) create SmootherFactory(s1, null) and SmootherFactory(null, s2)
130  // It may also happen that somewhere somebody set presmoother factory = postsmoother factory = (a)
131  // How do you do DeclareInput in this case? It could easily introduce a bug if a user does not check
132  // whether presmoother = postsmoother. A buggy code could look like that:
133  // RCP<SmootherFactory> s = rcp(new SmootherFactory(s1,s2));
134  // level.Request("PreSmoother", s.get());
135  // level.Request("PostSmoother", s.get());
136  // Get<RCP<SmootherBase> > pre = Get<RCP<SmootherBase> >("PreSmoother", s.get());
137  // Get<RCP<SmootherBase> > post = Get<RCP<SmootherBase> >("PostSmoother", s.get());
138  // This code would call DeclareInput in request mode twice, but as the Build method generates both Pre and Post
139  // smoothers, it would call DelcareInput in release mode only once, leaving requests.
140  // This code has another problem if s2 = Teuchos::null. In that case, despite the request for PostSmoother, the factory
141  // would not generate one, and second Get would throw. The real issue here is that given a Factory pointer
142  // there is no way to be sure that this factory would generate any of "PreSmoother" or "PostSmoother", unless you are
143  // able to cast it to SmootherFactory, do GetPrototypes and to check whether any of those is Teuchos::null.
144 
145  const Teuchos::ParameterList& pL = GetParameterList();
146 
147  RCP<SmootherPrototype> preSmoother, postSmoother;
148  ParameterList preSmootherParams, postSmootherParams;
149 
150  if ((preOrPost & PRE) && !preSmootherPrototype_.is_null()) {
151  if (currentLevel.IsAvailable("PreSmoother data", this))
152  preSmoother = currentLevel.Get<RCP<SmootherPrototype> >("PreSmoother data", this);
153  else
154  preSmoother = preSmootherPrototype_->Copy();
155 
156  int oldRank = -1;
157  if (!currentLevel.GetComm().is_null())
158  oldRank = preSmoother->SetProcRankVerbose(currentLevel.GetComm()->getRank());
159 
160  preSmoother->Setup(currentLevel);
161  preSmootherParams = preSmoother->GetParameterList();
162 
163  if (oldRank != -1)
164  preSmoother->SetProcRankVerbose(oldRank);
165 
166  currentLevel.Set<RCP<SmootherBase> >("PreSmoother", preSmoother, this);
167 
168  if (pL.get<bool>("keep smoother data"))
169  Set(currentLevel, "PreSmoother data", preSmoother);
170  }
171 
172  if ((preOrPost & POST) && !postSmootherPrototype_.is_null()) {
173  if (preOrPost == BOTH && preSmootherPrototype_ == postSmootherPrototype_) {
174  // Simple reuse
175  // Same prototypes for pre- and post-smoothers mean that we only need to call Setup only once
176  postSmoother = preSmoother;
177 
178  // else if (preOrPost == BOTH &&
179  // preSmootherPrototype_ != Teuchos::null &&
180  // preSmootherPrototype_->GetType() == postSmootherPrototype_->GetType()) {
181 
182  // // More complex reuse case: need implementation of CopyParameters() and a smoothers smart enough to know when parameters affect the setup phase.
183 
184  // // YES: post-smoother == pre-smoother
185  // // => copy the pre-smoother to avoid the setup phase of the post-smoother.
186  // postSmoother = preSmoother->Copy();
187  // // If the post-smoother parameters are different from
188  // // pre-smoother, the parameters stored in the post-smoother
189  // // prototype are copied in the new post-smoother object.
190  // postSmoother->CopyParameters(postSmootherPrototype_);
191  // // If parameters don't influence the Setup phase (it is the case
192  // // for Jacobi, Chebyshev...), PostSmoother is already setup. Nothing
193  // // more to do. In the case of ILU, parameters of the smoother
194  // // are in fact the parameters of the Setup phase. The call to
195  // // CopyParameters resets the smoother (only if parameters are
196  // // different) and we must call Setup() again.
197  // postSmoother->Setup(currentLevel);
198  // }
199 
200  // // TODO: if CopyParameters do not exist, do setup twice.
201 
202  } else {
203  if (currentLevel.IsAvailable("PostSmoother data", this)) {
204  postSmoother = currentLevel.Get<RCP<SmootherPrototype> >("PostSmoother data", this);
205  } else {
206  // No reuse:
207  // - either we only do postsmoothing without any presmoothing
208  // - or our postsmoother is different from presmoother
209  postSmoother = postSmootherPrototype_->Copy();
210  }
211 
212  int oldRank = -1;
213  if (!currentLevel.GetComm().is_null())
214  oldRank = postSmoother->SetProcRankVerbose(GetProcRankVerbose());
215 
216  postSmoother->Setup(currentLevel);
217  postSmootherParams = postSmoother->GetParameterList();
218 
219  if (oldRank != -1)
220  postSmoother->SetProcRankVerbose(oldRank);
221  }
222 
223  currentLevel.Set<RCP<SmootherBase> >("PostSmoother", postSmoother, this);
224 
225  if (pL.get<bool>("keep smoother data"))
226  Set(currentLevel, "PostSmoother data", postSmoother);
227  }
228 
229  ParameterList& paramList = const_cast<ParameterList&>(this->GetParameterList());
230  if (postSmoother == preSmoother && !preSmoother.is_null()) {
231  paramList.sublist("smoother", false) = preSmoother->GetParameterList();
232 
233  } else {
234  if (!preSmoother.is_null())
235  paramList.sublist("presmoother", false) = preSmootherParams;
236 
237  if (!postSmoother.is_null())
238  paramList.sublist("postsmoother", false) = postSmootherParams;
239  }
240 
241 } // Build()
242 
243 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
245  std::ostringstream out;
247  std::string preStr = (preSmootherPrototype_ == Teuchos::null) ? "null" : preSmootherPrototype_->description();
248  std::string postStr = (preSmootherPrototype_ == postSmootherPrototype_) ? "pre" : ((postSmootherPrototype_ == Teuchos::null) ? "null" : postSmootherPrototype_->description());
249  out << "{pre = " << preStr << ", post = " << postStr << "}";
250  return out.str();
251 }
252 
253 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
256 
257  if (verbLevel & Parameters0) {
258  out0 << "PreSmoother : ";
259  if (preSmootherPrototype_.is_null()) {
260  out0 << "null" << std::endl;
261  } else {
262  Teuchos::OSTab tab2(out);
263  preSmootherPrototype_->describe(out, verbLevel);
264  }
265 
266  out0 << "PostSmoother: ";
267  if (postSmootherPrototype_ == preSmootherPrototype_) {
268  out0 << "same as PreSmoother" << std::endl;
269  } else if (postSmootherPrototype_ == Teuchos::null) {
270  out0 << "null" << std::endl;
271  } else {
272  Teuchos::OSTab tab2(out);
273  postSmootherPrototype_->describe(out, verbLevel);
274  out0 << "PostSmoother is different than PreSmoother (not the same object)" << std::endl;
275  }
276  }
277 
278  if (verbLevel & Debug) {
279  if (preSmootherPrototype_ != Teuchos::null || postSmootherPrototype_ != Teuchos::null) {
280  out0 << "-" << std::endl;
281  }
282  if (preSmootherPrototype_ != Teuchos::null) {
283  out0 << "RCP<preSmootherPrototype_> : " << preSmootherPrototype_ << std::endl;
284  }
285  if (postSmootherPrototype_ != Teuchos::null) {
286  out0 << "RCP<postSmootherPrototype_>: " << postSmootherPrototype_ << std::endl;
287  }
288  }
289 }
290 
291 } // namespace MueLu
292 
293 // TODO: doc: setup done twice if PostSmoother object != PreSmoother object and no adv. reused capability
294 
295 // TODO ReUse: If only one smoother is missing, SmootherFactory can be smart and build only the missing smoother.
296 // TODO (optim): we can also reuse if preOrPost = post and preSmoother available in Level
297 // we can also reuse if preOrPost = pre and postSmoother available in Level
298 
299 #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)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
#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.
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:99
#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