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  // NOTE: Aggregates use the next level's Factory
202  ExportDataSetKeepFlagsNextLevel(H, aggregatesToPrint_, "Aggregates");
203 #ifdef HAVE_MUELU_INTREPID2
204  ExportDataSetKeepFlags(H, elementToNodeMapsToPrint_, "pcoarsen: element to node map");
205 #endif
206 
207  // Data to save only (these do not have a level, so we do all levels)
208  for (int i = 0; i < dataToSave_.size(); i++)
209  ExportDataSetKeepFlagsAll(H, dataToSave_[i]);
210 
211  int levelID = 0;
212  int lastLevelID = numDesiredLevel_ - 1;
213  bool isLastLevel = false;
214 
215  while (!isLastLevel) {
216  bool r = H.Setup(levelID,
217  LvlMngr(levelID - 1, lastLevelID),
218  LvlMngr(levelID, lastLevelID),
219  LvlMngr(levelID + 1, lastLevelID));
220  if (levelID < H.GetNumLevels())
221  H.GetLevel(levelID)->print(H.GetOStream(Developer), verbosity_);
222 
223  isLastLevel = r || (levelID == lastLevelID);
224  levelID++;
225  }
226  if (!matvecParams_.is_null())
227  H.SetMatvecParams(matvecParams_);
228  H.AllocateLevelMultiVectors(sizeOfMultiVectors_);
229  // Set hierarchy description.
230  // This is cached, but involves and MPI_Allreduce.
231  H.description();
232  H.describe(H.GetOStream(Runtime0), verbosity_);
233  H.CheckForEmptySmoothersAndCoarseSolve();
234 
235  // When we reuse hierarchy, it is necessary that we don't
236  // change the number of levels. We also cannot make requests
237  // for coarser levels, because we don't construct all the
238  // data on previous levels. For instance, let's say our first
239  // run constructed three levels. If we try to do requests during
240  // next setup for the fourth level, it would need Aggregates
241  // which we didn't construct for level 3 because we reused P.
242  // To fix this situation, we change the number of desired levels
243  // here.
244  numDesiredLevel_ = levelID;
245 
246  // Matrix prints
247  for (auto iter = matricesToPrint_.begin(); iter != matricesToPrint_.end(); iter++) {
248  WriteData<Matrix>(H, iter->second, iter->first);
249  }
250 
251  // Vectors, aggregates and all things we need to print manually
252  WriteData<MultiVector>(H, nullspaceToPrint_, "Nullspace");
253  WriteData<MultiVector>(H, coordinatesToPrint_, "Coordinates");
254  WriteDataAggregates(H, aggregatesToPrint_, "Aggregates");
255 
256 #ifdef HAVE_MUELU_INTREPID2
257  typedef Kokkos::DynRankView<LocalOrdinal, typename Node::device_type> FCi;
258  WriteDataFC<FCi>(H, elementToNodeMapsToPrint_, "pcoarsen: element to node map", "el2node");
259 #endif
260 
261 } // SetupHierarchy
262 
263 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
265  // NOTE: the order of 'if' statements is important
266  if (levelID == -1) // levelID = -1 corresponds to the finest level
267  return Teuchos::null;
268 
269  if (levelID == lastLevelID + 1) // levelID = 'lastLevelID+1' corresponds to the last level (i.e., no nextLevel)
270  return Teuchos::null;
271 
272  if (levelManagers_.size() == 0) { // default factory manager.
273  // The default manager is shared across levels, initialized only if needed and deleted with the HierarchyManager
274  static RCP<FactoryManagerBase> defaultMngr = rcp(new FactoryManager());
275  return defaultMngr;
276  }
277 
278  return GetFactoryManager(levelID);
279 }
280 
281 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
283  for (int i = 0; i < data.size(); ++i) {
284  if (data[i] < H.GetNumLevels()) {
285  RCP<Level> L = H.GetLevel(data[i]);
286  if (!L.is_null() && data[i] < levelManagers_.size())
287  L->AddKeepFlag(name, &*levelManagers_[data[i]]->GetFactory(name));
288  }
289  }
290 }
291 
292 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
294  for (int i = 0; i < data.size(); ++i) {
295  if (data[i] < H.GetNumLevels()) {
296  RCP<Level> L = H.GetLevel(data[i]);
297  if (!L.is_null() && data[i] + 1 < levelManagers_.size())
298  L->AddKeepFlag(name, &*levelManagers_[data[i] + 1]->GetFactory(name));
299  }
300  }
301 }
302 
303 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
305  for (int i = 0; i < H.GetNumLevels(); i++) {
306  RCP<Level> L = H.GetLevel(i);
307  if (!L.is_null() && i < levelManagers_.size())
308  L->AddKeepFlag(name, &*levelManagers_[i]->GetFactory(name));
309  }
310 }
311 
312 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
313 template <class T>
314 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteData(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
315  for (int i = 0; i < data.size(); ++i) {
316  std::string fileName;
317  if (H.getObjectLabel() != "")
318  fileName = H.getObjectLabel() + "_" + name + "_" + Teuchos::toString(data[i]) + ".m";
319  else
320  fileName = name + "_" + Teuchos::toString(data[i]) + ".m";
321 
322  if (data[i] < H.GetNumLevels()) {
323  RCP<Level> L = H.GetLevel(data[i]);
324  if (data[i] < levelManagers_.size() && L->IsAvailable(name, &*levelManagers_[data[i]]->GetFactory(name))) {
325  // Try generating factory
326  RCP<T> M = L->template Get<RCP<T>>(name, &*levelManagers_[data[i]]->GetFactory(name));
327  if (!M.is_null()) {
329  }
330  } else if (L->IsAvailable(name)) {
331  // Try nofactory
332  RCP<T> M = L->template Get<RCP<T>>(name);
333  if (!M.is_null()) {
335  }
336  }
337  }
338  }
339 }
340 
341 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
342 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteDataAggregates(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
343  for (int i = 0; i < data.size(); ++i) {
344  const std::string fileName = name + "_" + Teuchos::toString(data[i]) + ".m";
345 
346  if (data[i] < H.GetNumLevels()) {
347  RCP<Level> L = H.GetLevel(data[i]);
348 
349  // NOTE: Aggregates use the next level's factory
350  RCP<Aggregates> agg;
351  if (data[i] + 1 < H.GetNumLevels() && L->IsAvailable(name, &*levelManagers_[data[i] + 1]->GetFactory(name))) {
352  // Try generating factory
353  agg = L->template Get<RCP<Aggregates>>(name, &*levelManagers_[data[i] + 1]->GetFactory(name));
354  } else if (L->IsAvailable(name)) {
355  agg = L->template Get<RCP<Aggregates>>("Aggregates");
356  }
357  if (!agg.is_null()) {
358  std::ofstream ofs(fileName);
359  Teuchos::FancyOStream fofs(rcp(&ofs, false));
360  agg->print(fofs, Teuchos::VERB_EXTREME);
361  }
362  }
363  }
364 }
365 
366 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
367 template <class T>
368 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteDataFC(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name, const std::string& ofname) const {
369  for (int i = 0; i < data.size(); ++i) {
370  const std::string fileName = ofname + "_" + Teuchos::toString(data[i]) + ".m";
371 
372  if (data[i] < H.GetNumLevels()) {
373  RCP<Level> L = H.GetLevel(data[i]);
374 
375  if (L->IsAvailable(name)) {
376  RCP<T> M = L->template Get<RCP<T>>(name);
377  if (!M.is_null()) {
378  RCP<Matrix> A = L->template Get<RCP<Matrix>>("A");
379  RCP<const CrsGraph> AG = A->getCrsGraph();
380  WriteFieldContainer<T>(fileName, *M, *AG->getColMap());
381  }
382  }
383  }
384  }
385 }
386 
387 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
388 template <class T>
389 void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteFieldContainer(const std::string& fileName, T& fcont, const Map& colMap) const {
390  size_t num_els = (size_t)fcont.extent(0);
391  size_t num_vecs = (size_t)fcont.extent(1);
392 
393  // Generate rowMap
394  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());
395 
396  // Fill multivector to use *petra dump routines
397  RCP<GOMultiVector> vec = Xpetra::MultiVectorFactory<GO, LO, GO, NO>::Build(rowMap, num_vecs);
398 
399  for (size_t j = 0; j < num_vecs; j++) {
400  Teuchos::ArrayRCP<GO> v = vec->getDataNonConst(j);
401  for (size_t i = 0; i < num_els; i++)
402  v[i] = colMap.getGlobalElement(fcont(i, j));
403  }
404 
406 }
407 
408 } // namespace MueLu
409 
410 #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