MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_HierarchyManager_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_HIERARCHYMANAGER_DEF_HPP
11 #define MUELU_HIERARCHYMANAGER_DEF_HPP
12 
13 #include <string>
14 #include <map>
15 
16 #include <Teuchos_Array.hpp>
17 
18 #include <Xpetra_Operator.hpp>
19 #include <Xpetra_IO.hpp>
20 
21 #include "MueLu_ConfigDefs.hpp"
23 
24 #include "MueLu_Exceptions.hpp"
25 #include "MueLu_Aggregates.hpp"
26 #include "MueLu_Hierarchy.hpp"
28 #include "MueLu_Level.hpp"
29 #include "MueLu_MasterList.hpp"
30 #include "MueLu_PerfUtils.hpp"
31 
32 #ifdef HAVE_MUELU_INTREPID2
33 #include "Kokkos_DynRankView.hpp"
34 #endif
35 
36 namespace MueLu {
37 
38 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
40  : numDesiredLevel_(numDesiredLevel)
41  , maxCoarseSize_(MasterList::getDefault<int>("coarse: max size"))
42  , verbosity_(Medium)
43  , doPRrebalance_(MasterList::getDefault<bool>("repartition: rebalance P and R"))
44  , doPRViaCopyrebalance_(MasterList::getDefault<bool>("repartition: explicit via new copy rebalance P and R"))
45  , implicitTranspose_(MasterList::getDefault<bool>("transpose: use implicit"))
46  , fuseProlongationAndUpdate_(MasterList::getDefault<bool>("fuse prolongation and update"))
47  , suppressNullspaceDimensionCheck_(MasterList::getDefault<bool>("nullspace: suppress dimension check"))
48  , sizeOfMultiVectors_(MasterList::getDefault<int>("number of vectors"))
49  , graphOutputLevel_(-2) {}
50 
51 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
53  const int lastLevel = startLevel + numDesiredLevel - 1;
54  if (levelManagers_.size() < lastLevel + 1)
55  levelManagers_.resize(lastLevel + 1);
56 
57  for (int iLevel = startLevel; iLevel <= lastLevel; iLevel++)
58  levelManagers_[iLevel] = manager;
59 }
60 
61 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
63  // NOTE: last levelManager is used for all the remaining levels
64  return (levelID >= levelManagers_.size() ? levelManagers_[levelManagers_.size() - 1] : levelManagers_[levelID]);
65 }
66 
67 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
69  return levelManagers_.size();
70 }
71 
72 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
74  for (int i = 0; i < levelManagers_.size(); i++)
75  TEUCHOS_TEST_FOR_EXCEPTION(levelManagers_[i] == Teuchos::null, Exceptions::RuntimeError, "MueLu:HierarchyConfig::CheckConfig(): Undefined configuration for level:");
76 }
77 
78 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
79 RCP<MueLu::Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CreateHierarchy() const {
80  return rcp(new Hierarchy());
81 }
82 
83 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
84 RCP<MueLu::Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CreateHierarchy(const std::string& label) const {
85  return rcp(new Hierarchy(label));
86 }
87 
88 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
90  TEUCHOS_TEST_FOR_EXCEPTION(!H.GetLevel(0)->IsAvailable("A"), Exceptions::RuntimeError, "No fine level operator");
91 
92  RCP<Level> l0 = H.GetLevel(0);
93  RCP<Operator> Op = l0->Get<RCP<Operator>>("A");
94 
95  // Compare nullspace dimension to NumPDEs and throw/warn based on user input
96  if (l0->IsAvailable("Nullspace")) {
97  RCP<Matrix> A = Teuchos::rcp_dynamic_cast<Matrix>(Op);
98  if (A != Teuchos::null) {
99  RCP<MultiVector> nullspace = l0->Get<RCP<MultiVector>>("Nullspace");
100 
101  if (static_cast<size_t>(A->GetFixedBlockSize()) > nullspace->getNumVectors()) {
102  std::stringstream msg;
103  msg << "User-provided nullspace has fewer vectors ("
104  << nullspace->getNumVectors() << ") than number of PDE equations ("
105  << A->GetFixedBlockSize() << "). ";
106 
107  if (suppressNullspaceDimensionCheck_) {
108  msg << "It depends on the PDE, if this is a problem or not.";
109  this->GetOStream(Warnings0) << msg.str() << std::endl;
110  } else {
111  msg << "Add the missing nullspace vectors! (You can suppress this check. See the MueLu user guide for details.)";
112  TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(A->GetFixedBlockSize()) > nullspace->getNumVectors(), Exceptions::RuntimeError, msg.str());
113  }
114  }
115  } else {
116  this->GetOStream(Warnings0) << "Skipping dimension check of user-supplied nullspace because user-supplied operator is not a matrix" << std::endl;
117  }
118  }
119 
120 #ifdef HAVE_MUELU_DEBUG
121  // Reset factories' data used for debugging
122  for (int i = 0; i < levelManagers_.size(); i++)
123  levelManagers_[i]->ResetDebugData();
124 
125 #endif
126 
127  // Setup Matrix
128  // TODO: I should certainly undo this somewhere...
129 
130  Xpetra::UnderlyingLib lib = Op->getDomainMap()->lib();
131  H.setlib(lib);
132 
133  SetupOperator(*Op);
134  SetupExtra(H);
135 
136  // Setup Hierarchy
137  H.SetMaxCoarseSize(maxCoarseSize_);
139  if (graphOutputLevel_ >= 0 || graphOutputLevel_ == -1)
140  H.EnableGraphDumping("dep_graph", graphOutputLevel_);
141 
143  RCP<Matrix> Amat = rcp_dynamic_cast<Matrix>(Op);
144 
145  if (!Amat.is_null()) {
146  RCP<ParameterList> params = rcp(new ParameterList());
147  params->set("printLoadBalancingInfo", true);
148  params->set("printCommInfo", true);
149 
151  } else {
152  VerboseObject::GetOStream(Warnings1) << "Fine level operator is not a matrix, statistics are not available" << std::endl;
153  }
154  }
155 
156  H.SetPRrebalance(doPRrebalance_);
157  H.SetPRViaCopyrebalance(doPRViaCopyrebalance_);
158  H.SetImplicitTranspose(implicitTranspose_);
159  H.SetFuseProlongationAndUpdate(fuseProlongationAndUpdate_);
160 
161  H.Clear();
162 
163  // There are few issues with using Keep in the interpreter:
164  // 1. Hierarchy::Keep interface takes a name and a factory. If
165  // factories are different on different levels, the AddNewLevel() call
166  // in Hierarchy does not work properly, as it assume that factories are
167  // the same.
168  // 2. FactoryManager does not have a Keep option, only Hierarchy and
169  // Level have it
170  // 3. Interpreter constructs factory managers, but not levels. So we
171  // cannot set up Keep flags there.
172  //
173  // The solution implemented here does the following:
174  // 1. Construct hierarchy with dummy levels. This avoids
175  // Hierarchy::AddNewLevel() calls which will propagate wrong
176  // inheritance.
177  // 2. Interpreter constructs keep_ array with names and factories for
178  // that level
179  // 3. For each level, we call Keep(name, factory) for each keep_
180  for (int i = 0; i < numDesiredLevel_; i++) {
181  std::map<int, std::vector<keep_pair>>::const_iterator it = keep_.find(i);
182  if (it != keep_.end()) {
183  RCP<Level> l = H.GetLevel(i);
184  const std::vector<keep_pair>& keeps = it->second;
185  for (size_t j = 0; j < keeps.size(); j++)
186  l->Keep(keeps[j].first, keeps[j].second);
187  }
188  if (i < numDesiredLevel_ - 1) {
189  RCP<Level> newLevel = rcp(new Level());
190  H.AddLevel(newLevel);
191  }
192  }
193 
194  // Matrices to print
195  for (auto iter = matricesToPrint_.begin(); iter != matricesToPrint_.end(); iter++)
196  ExportDataSetKeepFlags(H, iter->second, iter->first);
197 
198  // Vectors, aggregates and other things that need special case handling
199  ExportDataSetKeepFlags(H, nullspaceToPrint_, "Nullspace");
200  ExportDataSetKeepFlags(H, coordinatesToPrint_, "Coordinates");
201  ExportDataSetKeepFlags(H, materialToPrint_, "Material");
202  // NOTE: Aggregates use the next level's Factory
203  ExportDataSetKeepFlagsNextLevel(H, aggregatesToPrint_, "Aggregates");
204 #ifdef HAVE_MUELU_INTREPID2
205  ExportDataSetKeepFlags(H, elementToNodeMapsToPrint_, "pcoarsen: element to node map");
206 #endif
207 
208  // Data to save only (these do not have a level, so we do all levels)
209  for (int i = 0; i < dataToSave_.size(); i++)
210  ExportDataSetKeepFlagsAll(H, dataToSave_[i]);
211 
212  int levelID = 0;
213  int lastLevelID = numDesiredLevel_ - 1;
214  bool isLastLevel = false;
215 
216  while (!isLastLevel) {
217  bool r = H.Setup(levelID,
218  LvlMngr(levelID - 1, lastLevelID),
219  LvlMngr(levelID, lastLevelID),
220  LvlMngr(levelID + 1, lastLevelID));
221  if (levelID < H.GetNumLevels())
222  H.GetLevel(levelID)->print(H.GetOStream(Developer), verbosity_);
223 
224  isLastLevel = r || (levelID == lastLevelID);
225  levelID++;
226  }
227  if (!matvecParams_.is_null())
228  H.SetMatvecParams(matvecParams_);
229  H.AllocateLevelMultiVectors(sizeOfMultiVectors_);
230  // Set hierarchy description.
231  // This is cached, but involves and MPI_Allreduce.
232  H.description();
233  H.describe(H.GetOStream(Runtime0), verbosity_);
234  H.CheckForEmptySmoothersAndCoarseSolve();
235 
236  // When we reuse hierarchy, it is necessary that we don't
237  // change the number of levels. We also cannot make requests
238  // for coarser levels, because we don't construct all the
239  // data on previous levels. For instance, let's say our first
240  // run constructed three levels. If we try to do requests during
241  // next setup for the fourth level, it would need Aggregates
242  // which we didn't construct for level 3 because we reused P.
243  // To fix this situation, we change the number of desired levels
244  // here.
245  numDesiredLevel_ = levelID;
246 
247  // Matrix prints
248  for (auto iter = matricesToPrint_.begin(); iter != matricesToPrint_.end(); iter++) {
249  WriteData<Matrix>(H, iter->second, iter->first);
250  }
251 
252  // Vectors, aggregates and all things we need to print manually
253  WriteData<MultiVector>(H, nullspaceToPrint_, "Nullspace");
254  WriteData<MultiVector>(H, coordinatesToPrint_, "Coordinates");
255  WriteData<MultiVector>(H, materialToPrint_, "Material");
256  WriteDataAggregates(H, aggregatesToPrint_, "Aggregates");
257 
258 #ifdef HAVE_MUELU_INTREPID2
259  typedef Kokkos::DynRankView<LocalOrdinal, typename Node::device_type> FCi;
260  WriteDataFC<FCi>(H, elementToNodeMapsToPrint_, "pcoarsen: element to node map", "el2node");
261 #endif
262 
263 } // SetupHierarchy
264 
265 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
267  // NOTE: the order of 'if' statements is important
268  if (levelID == -1) // levelID = -1 corresponds to the finest level
269  return Teuchos::null;
270 
271  if (levelID == lastLevelID + 1) // levelID = 'lastLevelID+1' corresponds to the last level (i.e., no nextLevel)
272  return Teuchos::null;
273 
274  if (levelManagers_.size() == 0) { // default factory manager.
275  // The default manager is shared across levels, initialized only if needed and deleted with the HierarchyManager
276  static RCP<FactoryManagerBase> defaultMngr = rcp(new FactoryManager());
277  return defaultMngr;
278  }
279 
280  return GetFactoryManager(levelID);
281 }
282 
283 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
285  for (int i = 0; i < data.size(); ++i) {
286  if (data[i] < H.GetNumLevels()) {
287  RCP<Level> L = H.GetLevel(data[i]);
288  if (!L.is_null() && data[i] < levelManagers_.size())
289  L->AddKeepFlag(name, &*levelManagers_[data[i]]->GetFactory(name));
290  }
291  }
292 }
293 
294 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
296  for (int i = 0; i < data.size(); ++i) {
297  if (data[i] < H.GetNumLevels()) {
298  RCP<Level> L = H.GetLevel(data[i]);
299  if (!L.is_null() && data[i] + 1 < levelManagers_.size())
300  L->AddKeepFlag(name, &*levelManagers_[data[i] + 1]->GetFactory(name));
301  }
302  }
303 }
304 
305 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
307  for (int i = 0; i < H.GetNumLevels(); i++) {
308  RCP<Level> L = H.GetLevel(i);
309  if (!L.is_null() && i < levelManagers_.size())
310  L->AddKeepFlag(name, &*levelManagers_[i]->GetFactory(name));
311  }
312 }
313 
314 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
315 template <class T>
316 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteData(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
317  for (int i = 0; i < data.size(); ++i) {
318  std::string fileName;
319  if (H.getObjectLabel() != "")
320  fileName = H.getObjectLabel() + "_" + name + "_" + Teuchos::toString(data[i]) + ".m";
321  else
322  fileName = name + "_" + Teuchos::toString(data[i]) + ".m";
323 
324  if (data[i] < H.GetNumLevels()) {
325  RCP<Level> L = H.GetLevel(data[i]);
326  if (data[i] < levelManagers_.size() && L->IsAvailable(name, &*levelManagers_[data[i]]->GetFactory(name))) {
327  // Try generating factory
328  RCP<T> M = L->template Get<RCP<T>>(name, &*levelManagers_[data[i]]->GetFactory(name));
329  if (!M.is_null()) {
331  }
332  } else if (L->IsAvailable(name)) {
333  // Try nofactory
334  RCP<T> M = L->template Get<RCP<T>>(name);
335  if (!M.is_null()) {
337  }
338  }
339  }
340  }
341 }
342 
343 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
344 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteDataAggregates(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
345  for (int i = 0; i < data.size(); ++i) {
346  const 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 
351  // NOTE: Aggregates use the next level's factory
352  RCP<Aggregates> agg;
353  if (data[i] + 1 < H.GetNumLevels() && L->IsAvailable(name, &*levelManagers_[data[i] + 1]->GetFactory(name))) {
354  // Try generating factory
355  agg = L->template Get<RCP<Aggregates>>(name, &*levelManagers_[data[i] + 1]->GetFactory(name));
356  } else if (L->IsAvailable(name)) {
357  agg = L->template Get<RCP<Aggregates>>("Aggregates");
358  }
359  if (!agg.is_null()) {
360  std::ofstream ofs(fileName);
361  Teuchos::FancyOStream fofs(rcp(&ofs, false));
362  agg->print(fofs, Teuchos::VERB_EXTREME);
363  }
364  }
365  }
366 }
367 
368 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
369 template <class T>
370 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteDataFC(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name, const std::string& ofname) const {
371  for (int i = 0; i < data.size(); ++i) {
372  const std::string fileName = ofname + "_" + Teuchos::toString(data[i]) + ".m";
373 
374  if (data[i] < H.GetNumLevels()) {
375  RCP<Level> L = H.GetLevel(data[i]);
376 
377  if (L->IsAvailable(name)) {
378  RCP<T> M = L->template Get<RCP<T>>(name);
379  if (!M.is_null()) {
380  RCP<Matrix> A = L->template Get<RCP<Matrix>>("A");
381  RCP<const CrsGraph> AG = A->getCrsGraph();
382  WriteFieldContainer<T>(fileName, *M, *AG->getColMap());
383  }
384  }
385  }
386  }
387 }
388 
389 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
390 template <class T>
391 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteFieldContainer(const std::string& fileName, T& fcont, const Map& colMap) const {
392  size_t num_els = (size_t)fcont.extent(0);
393  size_t num_vecs = (size_t)fcont.extent(1);
394 
395  // Generate rowMap
396  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());
397 
398  // Fill multivector to use *petra dump routines
399  RCP<GOMultiVector> vec = Xpetra::MultiVectorFactory<GO, LO, GO, NO>::Build(rowMap, num_vecs);
400 
401  for (size_t j = 0; j < num_vecs; j++) {
402  Teuchos::ArrayRCP<GO> v = vec->getDataNonConst(j);
403  for (size_t i = 0; i < num_els; i++)
404  v[i] = colMap.getGlobalElement(fcont(i, j));
405  }
406 
408 }
409 
410 } // namespace MueLu
411 
412 #endif
Important warning messages (one line)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
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 WriteDataAggregates(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
void ExportDataSetKeepFlags(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
RCP< FactoryManagerBase > GetFactoryManager(int levelID) const
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static void Write(const std::string &fileName, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &M)
Print information primarily of interest to developers.
void AddFactoryManager(int startLevel, int numDesiredLevel, RCP< FactoryManagerBase > manager)
One-liner description of what is happening.
Teuchos::RCP< FactoryManagerBase > LvlMngr(int levelID, int lastLevelID) const
Static class that holds the complete list of valid MueLu parameters.
Print even more statistics.
virtual RCP< Hierarchy > CreateHierarchy() const
Create an empty Hierarchy object.
Additional warnings.
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)
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.
void ExportDataSetKeepFlagsAll(Hierarchy &H, const std::string &name) const
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
virtual void SetupHierarchy(Hierarchy &H) const
Setup Hierarchy object.
TransListIter iter
size_type size() const
HierarchyManager(int numDesiredLevel=MasterList::getDefault< int >("max levels"))
Constructor.
void WriteDataFC(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name, const std::string &ofname) const
void WriteFieldContainer(const std::string &fileName, T &fcont, const Map &colMap) const
std::string toString(const T &t)
void ExportDataSetKeepFlagsNextLevel(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const