MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_HierarchyManager.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_HIERARCHYMANAGER_DECL_HPP
47 #define MUELU_HIERARCHYMANAGER_DECL_HPP
48 
49 #include <string>
50 #include <map>
51 
52 #include <Teuchos_Array.hpp>
53 
54 #include <Xpetra_Operator.hpp>
55 #include <Xpetra_IO.hpp>
56 
57 #include "MueLu_ConfigDefs.hpp"
58 
59 #include "MueLu_Exceptions.hpp"
60 #include "MueLu_Hierarchy.hpp"
62 #include "MueLu_Level.hpp"
63 #include "MueLu_MasterList.hpp"
64 #include "MueLu_PerfUtils.hpp"
65 
66 #ifdef HAVE_MUELU_INTREPID2
67 #include "Kokkos_DynRankView.hpp"
68 #endif
69 
70 namespace MueLu {
71 
72  // This class stores the configuration of a Hierarchy.
73  // The class also provides an algorithm to build a Hierarchy from the configuration.
74  //
75  // See also: FactoryManager
76  //
77  template <class Scalar = DefaultScalar,
80  class Node = DefaultNode>
81  class HierarchyManager : public HierarchyFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node> {
82 #undef MUELU_HIERARCHYMANAGER_SHORT
83 #include "MueLu_UseShortNames.hpp"
84  typedef std::pair<std::string, const FactoryBase*> keep_pair;
85 
86  public:
87 
89  HierarchyManager(int numDesiredLevel = MasterList::getDefault<int>("max levels")) :
90  numDesiredLevel_ (numDesiredLevel),
91  maxCoarseSize_ (MasterList::getDefault<int>("coarse: max size")),
93  doPRrebalance_ (MasterList::getDefault<bool>("repartition: rebalance P and R")),
94  implicitTranspose_ (MasterList::getDefault<bool>("transpose: use implicit")),
95  fuseProlongationAndUpdate_ (MasterList::getDefault<bool>("fuse prolongation and update")),
96  graphOutputLevel_(-1) { }
97 
99  virtual ~HierarchyManager() { }
100 
102  void AddFactoryManager(int startLevel, int numDesiredLevel, RCP<FactoryManagerBase> manager) {
103  const int lastLevel = startLevel + numDesiredLevel - 1;
104  if (levelManagers_.size() < lastLevel + 1)
105  levelManagers_.resize(lastLevel + 1);
106 
107  for (int iLevel = startLevel; iLevel <= lastLevel; iLevel++)
108  levelManagers_[iLevel] = manager;
109  }
110 
113  // NOTE: last levelManager is used for all the remaining levels
114  return (levelID >= levelManagers_.size() ? levelManagers_[levelManagers_.size()-1] : levelManagers_[levelID]);
115  }
116 
118  size_t getNumFactoryManagers() const {
119  return levelManagers_.size();
120  }
121 
123  void CheckConfig() {
124  for (int i = 0; i < levelManagers_.size(); i++)
125  TEUCHOS_TEST_FOR_EXCEPTION(levelManagers_[i] == Teuchos::null, Exceptions::RuntimeError, "MueLu:HierarchyConfig::CheckConfig(): Undefined configuration for level:");
126  }
127 
129 
130  virtual RCP<Hierarchy> CreateHierarchy() const {
131  return rcp(new Hierarchy());
132  }
133 
134  virtual RCP<Hierarchy> CreateHierarchy(const std::string& label) const {
135  return rcp(new Hierarchy(label));
136  }
137 
139  virtual void SetupHierarchy(Hierarchy& H) const {
140  TEUCHOS_TEST_FOR_EXCEPTION(!H.GetLevel(0)->IsAvailable("A"), Exceptions::RuntimeError, "No fine level operator");
141 
142  RCP<Level> l0 = H.GetLevel(0);
143  RCP<Operator> Op = l0->Get<RCP<Operator> >("A");
144  // Check that user-supplied nullspace dimension is at least as large as NumPDEs
145  if (l0->IsAvailable("Nullspace")) {
146  RCP<Matrix> A = Teuchos::rcp_dynamic_cast<Matrix>(Op);
147  if (A != Teuchos::null) {
148  Teuchos::RCP<MultiVector> nullspace = l0->Get<RCP<MultiVector> >("Nullspace");
149  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(A->GetFixedBlockSize()) > nullspace->getNumVectors(), Exceptions::RuntimeError, "user-provided nullspace has fewer vectors (" << nullspace->getNumVectors() << ") than number of PDE equations (" << A->GetFixedBlockSize() << ")");
150  } else {
151  this->GetOStream(Warnings0) << "Skipping dimension check of user-supplied nullspace because user-supplied operator is not a matrix" << std::endl;
152  }
153  }
154 
155 #ifdef HAVE_MUELU_DEBUG
156  // Reset factories' data used for debugging
157  for (int i = 0; i < levelManagers_.size(); i++)
158  levelManagers_[i]->ResetDebugData();
159 
160 #endif
161 
162  // Setup Matrix
163  // TODO: I should certainly undo this somewhere...
164 
165  Xpetra::UnderlyingLib lib = Op->getDomainMap()->lib();
166  H.setlib(lib);
167 
168  SetupOperator(*Op);
169  SetupExtra(H);
170 
171  // Setup Hierarchy
174  if (graphOutputLevel_ >= 0)
175  H.EnableGraphDumping("dep_graph.dot", graphOutputLevel_);
176 
178  RCP<Matrix> Amat = rcp_dynamic_cast<Matrix>(Op);
179 
180  if (!Amat.is_null()) {
181  RCP<ParameterList> params = rcp(new ParameterList());
182  params->set("printLoadBalancingInfo", true);
183  params->set("printCommInfo", true);
184 
186  } else {
187  VerboseObject::GetOStream(Warnings1) << "Fine level operator is not a matrix, statistics are not available" << std::endl;
188  }
189  }
190 
194 
195  H.Clear();
196 
197  // There are few issues with using Keep in the interpreter:
198  // 1. Hierarchy::Keep interface takes a name and a factory. If
199  // factories are different on different levels, the AddNewLevel() call
200  // in Hierarchy does not work properly, as it assume that factories are
201  // the same.
202  // 2. FactoryManager does not have a Keep option, only Hierarchy and
203  // Level have it
204  // 3. Interpreter constructs factory managers, but not levels. So we
205  // cannot set up Keep flags there.
206  //
207  // The solution implemented here does the following:
208  // 1. Construct hierarchy with dummy levels. This avoids
209  // Hierarchy::AddNewLevel() calls which will propagate wrong
210  // inheritance.
211  // 2. Interpreter constructs keep_ array with names and factories for
212  // that level
213  // 3. For each level, we call Keep(name, factory) for each keep_
214  for (int i = 0; i < numDesiredLevel_; i++) {
215  std::map<int, std::vector<keep_pair> >::const_iterator it = keep_.find(i);
216  if (it != keep_.end()) {
217  RCP<Level> l = H.GetLevel(i);
218  const std::vector<keep_pair>& keeps = it->second;
219  for (size_t j = 0; j < keeps.size(); j++)
220  l->Keep(keeps[j].first, keeps[j].second);
221  }
222  if (i < numDesiredLevel_-1) {
223  RCP<Level> newLevel = rcp(new Level());
224  H.AddLevel(newLevel);
225  }
226  }
230  ExportDataSetKeepFlags(H, nullspaceToPrint_, "Nullspace");
231  ExportDataSetKeepFlags(H, coordinatesToPrint_, "Coordinates");
232 #ifdef HAVE_MUELU_INTREPID2
233  ExportDataSetKeepFlags(H,elementToNodeMapsToPrint_, "pcoarsen: element to node map");
234 #endif
235 
236  int levelID = 0;
237  int lastLevelID = numDesiredLevel_ - 1;
238  bool isLastLevel = false;
239 
240  while (!isLastLevel) {
241  bool r = H.Setup(levelID,
242  LvlMngr(levelID-1, lastLevelID),
243  LvlMngr(levelID, lastLevelID),
244  LvlMngr(levelID+1, lastLevelID));
245 
246  isLastLevel = r || (levelID == lastLevelID);
247  levelID++;
248  }
249  if (!matvecParams_.is_null())
251  // FIXME: Should allow specification of NumVectors on parameterlist
254 
255  // When we reuse hierarchy, it is necessary that we don't
256  // change the number of levels. We also cannot make requests
257  // for coarser levels, because we don't construct all the
258  // data on previous levels. For instance, let's say our first
259  // run constructed three levels. If we try to do requests during
260  // next setup for the fourth level, it would need Aggregates
261  // which we didn't construct for level 3 because we reused P.
262  // To fix this situation, we change the number of desired levels
263  // here.
264  numDesiredLevel_ = levelID;
265 
266  WriteData<Matrix>(H, matricesToPrint_, "A");
267  WriteData<Matrix>(H, prolongatorsToPrint_, "P");
268  WriteData<Matrix>(H, restrictorsToPrint_, "R");
269  WriteData<MultiVector>(H, nullspaceToPrint_, "Nullspace");
270  WriteData<MultiVector>(H, coordinatesToPrint_, "Coordinates");
271 #ifdef HAVE_MUELU_INTREPID2
272  typedef Kokkos::DynRankView<LocalOrdinal,typename Node::device_type> FCi;
273  WriteDataFC<FCi>(H,elementToNodeMapsToPrint_, "pcoarsen: element to node map","el2node");
274 #endif
275 
276 
277  } //SetupHierarchy
278 
280 
281  typedef std::map<std::string, RCP<const FactoryBase> > FactoryMap;
282 
283  protected: //TODO: access function
284 
286  virtual void SetupOperator(Operator& /* Op */) const { }
287 
289  // TODO: merge with SetupMatrix ?
290  virtual void SetupExtra(Hierarchy& /* H */) const { }
291 
292  // TODO this was private
293  // Used in SetupHierarchy() to access levelManagers_
294  // Inputs i=-1 and i=size() are allowed to simplify calls to hierarchy->Setup()
295  Teuchos::RCP<FactoryManagerBase> LvlMngr(int levelID, int lastLevelID) const {
296  // NOTE: the order of 'if' statements is important
297  if (levelID == -1) // levelID = -1 corresponds to the finest level
298  return Teuchos::null;
299 
300  if (levelID == lastLevelID+1) // levelID = 'lastLevelID+1' corresponds to the last level (i.e., no nextLevel)
301  return Teuchos::null;
302 
303  if (levelManagers_.size() == 0) { // default factory manager.
304  // The default manager is shared across levels, initialized only if needed and deleted with the HierarchyManager
305  static RCP<FactoryManagerBase> defaultMngr = rcp(new FactoryManager());
306  return defaultMngr;
307  }
308 
309  return GetFactoryManager(levelID);
310  }
311 
312  // Hierarchy parameters
313  mutable int numDesiredLevel_;
327 
328  std::map<int, std::vector<keep_pair> > keep_;
329 
330  private:
331  // Set the keep flags for Export Data
332  void ExportDataSetKeepFlags(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
333  for (int i = 0; i < data.size(); ++i) {
334  if (data[i] < H.GetNumLevels()) {
335  RCP<Level> L = H.GetLevel(data[i]);
336  if(!L.is_null() && data[i] < levelManagers_.size())
337  L->AddKeepFlag(name, &*levelManagers_[data[i]]->GetFactory(name));
338  }
339  }
340  }
341 
342 
343  template<class T>
344  void WriteData(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
345  for (int i = 0; i < data.size(); ++i) {
346  std::string fileName = name + "_" + Teuchos::toString(data[i]) + ".m";
347 
348  if (data[i] < H.GetNumLevels()) {
349  RCP<Level> L = H.GetLevel(data[i]);
350  if (data[i] < levelManagers_.size() && L->IsAvailable(name,&*levelManagers_[data[i]]->GetFactory(name))) {
351  // Try generating factory
352  RCP<T> M = L->template Get< RCP<T> >(name,&*levelManagers_[data[i]]->GetFactory(name));
353  if (!M.is_null()) {
355  }
356  }
357  else if (L->IsAvailable(name)) {
358  // Try nofactory
359  RCP<T> M = L->template Get< RCP<T> >(name);
360  if (!M.is_null()) {
362  }
363  }
364 
365  }
366  }
367  }
368 
369 
370  template<class T>
371  void WriteDataFC(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name, const std::string & ofname) const {
372  for (int i = 0; i < data.size(); ++i) {
373  const std::string fileName = ofname + "_" + Teuchos::toString(data[i]) + ".m";
374 
375  if (data[i] < H.GetNumLevels()) {
376  RCP<Level> L = H.GetLevel(data[i]);
377 
378  if (L->IsAvailable(name)) {
379  RCP<T> M = L->template Get< RCP<T> >(name);
380  if (!M.is_null()) {
381  RCP<Matrix> A = L->template Get<RCP<Matrix> >("A");
382  RCP<const CrsGraph> AG = A->getCrsGraph();
383  WriteFieldContainer<T>(fileName,*M,*AG->getColMap());
384  }
385  }
386  }
387  }
388  }
389 
390  // For dumping an IntrepidPCoarsening element-to-node map to disk
391  template<class T>
392  void WriteFieldContainer(const std::string& fileName, T & fcont,const Map &colMap) const {
393  typedef LocalOrdinal LO;
394  typedef GlobalOrdinal GO;
395  typedef Node NO;
396  typedef Xpetra::MultiVector<GO,LO,GO,NO> GOMultiVector;
397 
398  size_t num_els = (size_t) fcont.extent(0);
399  size_t num_vecs =(size_t) fcont.extent(1);
400 
401  // Generate rowMap
402  Teuchos::RCP<const Map> rowMap = Xpetra::MapFactory<LO,GO,NO>::Build(colMap.lib(),Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),fcont.extent(0),colMap.getIndexBase(),colMap.getComm());
403 
404  // Fill multivector to use *petra dump routines
406 
407  for(size_t j=0; j<num_vecs; j++) {
408  Teuchos::ArrayRCP<GO> v = vec->getDataNonConst(j);
409  for(size_t i=0; i<num_els; i++)
410  v[i] = colMap.getGlobalElement(fcont(i,j));
411  }
412 
413  Xpetra::IO<GO,LO,GO,NO>::Write(fileName,*vec);
414  }
415 
416 
417 
418  // Levels
419  Array<RCP<FactoryManagerBase> > levelManagers_; // one FactoryManager per level (the last levelManager is used for all the remaining levels)
420 
421  }; // class HierarchyManager
422 
423 } // namespace MueLu
424 
425 #define MUELU_HIERARCHYMANAGER_SHORT
426 #endif // MUELU_HIERARCHYMANAGER_HPP
427 
428 //TODO: split into _decl/_def
429 // TODO: default value for first param (FactoryManager()) should not be duplicated (code maintainability)
virtual void SetupExtra(Hierarchy &) const
Setup extra data.
Important warning messages (one line)
This class specifies the default factory that should generate some data on a Level if the data does n...
Teuchos::Array< int > matricesToPrint_
MueLu::DefaultLocalOrdinal LocalOrdinal
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
KokkosClassic::DefaultNode::DefaultNodeType DefaultNode
RCP< Level > & GetLevel(const int levelID=0)
Retrieve a certain level from hierarchy.
static Teuchos::RCP< MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Build(const Teuchos::RCP< const Map< LocalOrdinal, GlobalOrdinal, Node >> &map, size_t NumVectors, bool zeroOut=true)
void ExportDataSetKeepFlags(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
GlobalOrdinal GO
virtual RCP< Hierarchy > CreateHierarchy(const std::string &label) const
Create a labeled empty Hierarchy object.
void AddLevel(const RCP< Level > &level)
Add a level at the end of the hierarchy.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Teuchos::Array< int > elementToNodeMapsToPrint_
static void Write(const std::string &fileName, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &M)
void SetMaxCoarseSize(Xpetra::global_size_t maxCoarseSize)
void AddFactoryManager(int startLevel, int numDesiredLevel, RCP< FactoryManagerBase > manager)
LocalOrdinal LO
One-liner description of what is happening.
void Clear(int startLevel=0)
Clear impermanent data from previous setup.
void SetFuseProlongationAndUpdate(const bool &fuse)
std::map< std::string, RCP< const FactoryBase > > FactoryMap
Static class that holds the complete list of valid MueLu parameters.
void AllocateLevelMultiVectors(int numvecs)
Teuchos::RCP< FactoryManagerBase > LvlMngr(int levelID, int lastLevelID) const
Print even more statistics.
Additional warnings.
Teuchos::RCP< Teuchos::ParameterList > matvecParams_
void WriteData(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
static void SetDefaultVerbLevel(const VerbLevel defaultVerbLevel)
Set the default (global) verbosity level.
size_t getNumFactoryManagers() const
returns number of factory managers stored in levelManagers_ vector.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Teuchos::Array< int > nullspaceToPrint_
static Teuchos::RCP< Map< LocalOrdinal, GlobalOrdinal, Node > > Build(UnderlyingLib lib, global_size_t numGlobalElements, GlobalOrdinal indexBase, const Teuchos::RCP< const Teuchos::Comm< int >> &comm, LocalGlobal lg=Xpetra::GloballyDistributed)
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
Array< RCP< FactoryManagerBase > > levelManagers_
RCP< FactoryManagerBase > GetFactoryManager(int levelID) const
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
void SetPRrebalance(bool doPRrebalance)
size_t global_size_t
void SetMatvecParams(RCP< ParameterList > matvecParams)
virtual void SetupOperator(Operator &) const
Setup Matrix object.
void SetImplicitTranspose(const bool &implicit)
Teuchos::Array< int > prolongatorsToPrint_
size_type size() const
Teuchos::Array< int > coordinatesToPrint_
std::map< int, std::vector< keep_pair > > keep_
HierarchyManager(int numDesiredLevel=MasterList::getDefault< int >("max levels"))
Exception throws to report errors in the internal logical of the program.
std::pair< std::string, const FactoryBase * > keep_pair
void describe(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the Hierarchy with some verbosity level to a FancyOStream object.
void WriteDataFC(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name, const std::string &ofname) const
void setlib(Xpetra::UnderlyingLib inlib)
Xpetra::global_size_t maxCoarseSize_
virtual RCP< Hierarchy > CreateHierarchy() const
Create an empty Hierarchy object.
bool Setup(int coarseLevelID, const RCP< const FactoryManagerBase > fineLevelManager, const RCP< const FactoryManagerBase > coarseLevelManager, const RCP< const FactoryManagerBase > nextLevelManager=Teuchos::null)
Multi-level setup phase: build a new level of the hierarchy.
void WriteFieldContainer(const std::string &fileName, T &fcont, const Map &colMap) const
Teuchos::Array< int > restrictorsToPrint_
void EnableGraphDumping(const std::string &filename, int levelID=1)
Provides methods to build a multigrid hierarchy and apply multigrid cycles.
std::string toString(const T &t)
virtual void SetupHierarchy(Hierarchy &H) const
Setup Hierarchy object.
bool is_null() const