MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_Hierarchy_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_HIERARCHY_DEF_HPP
11 #define MUELU_HIERARCHY_DEF_HPP
12 
13 #include <time.h>
14 
15 #include <algorithm>
16 #include <sstream>
17 
18 #include <Xpetra_Matrix.hpp>
19 #include <Xpetra_MultiVectorFactory.hpp>
20 #include <Xpetra_Operator.hpp>
21 #include <Xpetra_IO.hpp>
22 
23 #include "MueLu_Hierarchy_decl.hpp"
24 
25 #include "MueLu_FactoryManager.hpp"
26 #include "MueLu_HierarchyUtils.hpp"
27 #include "MueLu_TopRAPFactory.hpp"
28 #include "MueLu_TopSmootherFactory.hpp"
29 #include "MueLu_Level.hpp"
30 #include "MueLu_Monitor.hpp"
31 #include "MueLu_PerfUtils.hpp"
32 #include "MueLu_PFactory.hpp"
33 #include "MueLu_SmootherFactory.hpp"
34 #include "MueLu_SmootherBase.hpp"
35 
36 #include "Teuchos_TimeMonitor.hpp"
37 
38 namespace MueLu {
39 
40 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
42  : maxCoarseSize_(GetDefaultMaxCoarseSize())
43  , implicitTranspose_(GetDefaultImplicitTranspose())
44  , fuseProlongationAndUpdate_(GetDefaultFuseProlongationAndUpdate())
45  , doPRrebalance_(GetDefaultPRrebalance())
46  , doPRViaCopyrebalance_(false)
47  , isPreconditioner_(true)
48  , Cycle_(GetDefaultCycle())
49  , WCycleStartLevel_(0)
50  , scalingFactor_(Teuchos::ScalarTraits<double>::one())
51  , lib_(Xpetra::UseTpetra)
52  , isDumpingEnabled_(false)
53  , dumpLevel_(-2)
54  , rate_(-1)
55  , sizeOfAllocatedLevelMultiVectors_(0) {
56  AddLevel(rcp(new Level));
57 }
58 
59 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
61  : Hierarchy() {
62  setObjectLabel(label);
63  Levels_[0]->setObjectLabel(label);
64 }
65 
66 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
68  : maxCoarseSize_(GetDefaultMaxCoarseSize())
69  , implicitTranspose_(GetDefaultImplicitTranspose())
70  , fuseProlongationAndUpdate_(GetDefaultFuseProlongationAndUpdate())
71  , doPRrebalance_(GetDefaultPRrebalance())
72  , doPRViaCopyrebalance_(false)
73  , isPreconditioner_(true)
74  , Cycle_(GetDefaultCycle())
75  , WCycleStartLevel_(0)
76  , scalingFactor_(Teuchos::ScalarTraits<double>::one())
77  , isDumpingEnabled_(false)
78  , dumpLevel_(-2)
79  , rate_(-1)
80  , sizeOfAllocatedLevelMultiVectors_(0) {
81  lib_ = A->getDomainMap()->lib();
82 
83  RCP<Level> Finest = rcp(new Level);
84  AddLevel(Finest);
85 
86  Finest->Set("A", A);
87 }
88 
89 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
91  : Hierarchy(A) {
92  setObjectLabel(label);
93  Levels_[0]->setObjectLabel(label);
94 }
95 
96 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
98 
99 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
101  int levelID = LastLevelID() + 1; // ID of the inserted level
102 
103  if (level->GetLevelID() != -1 && (level->GetLevelID() != levelID))
104  GetOStream(Warnings1) << "Hierarchy::AddLevel(): Level with ID=" << level->GetLevelID() << " have been added at the end of the hierarchy\n but its ID have been redefined"
105  << " because last level ID of the hierarchy was " << LastLevelID() << "." << std::endl;
106 
107  Levels_.push_back(level);
108  level->SetLevelID(levelID);
109  level->setlib(lib_);
110 
111  level->SetPreviousLevel((levelID == 0) ? Teuchos::null : Levels_[LastLevelID() - 1]);
112  level->setObjectLabel(this->getObjectLabel());
113 }
114 
115 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
117  RCP<Level> newLevel = Levels_[LastLevelID()]->Build(); // new coarse level, using copy constructor
118  newLevel->setlib(lib_);
119  this->AddLevel(newLevel); // add to hierarchy
120 }
121 
122 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
124  TEUCHOS_TEST_FOR_EXCEPTION(levelID < 0 || levelID > LastLevelID(), Exceptions::RuntimeError,
125  "MueLu::Hierarchy::GetLevel(): invalid input parameter value: LevelID = " << levelID);
126  return Levels_[levelID];
127 }
128 
129 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
131  return Levels_.size();
132 }
133 
134 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
136  RCP<Operator> A = Levels_[0]->template Get<RCP<Operator>>("A");
137  RCP<const Teuchos::Comm<int>> comm = A->getDomainMap()->getComm();
138 
139  int numLevels = GetNumLevels();
140  int numGlobalLevels;
141  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, numLevels, Teuchos::ptr(&numGlobalLevels));
142 
143  return numGlobalLevels;
144 }
145 
146 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
148  double totalNnz = 0, lev0Nnz = 1;
149  for (int i = 0; i < GetNumLevels(); ++i) {
150  TEUCHOS_TEST_FOR_EXCEPTION(!(Levels_[i]->IsAvailable("A")), Exceptions::RuntimeError,
151  "Operator complexity cannot be calculated because A is unavailable on level " << i);
152  RCP<Operator> A = Levels_[i]->template Get<RCP<Operator>>("A");
153  if (A.is_null())
154  break;
155 
156  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
157  if (Am.is_null()) {
158  GetOStream(Warnings0) << "Some level operators are not matrices, operator complexity calculation aborted" << std::endl;
159  return 0.0;
160  }
161 
162  totalNnz += as<double>(Am->getGlobalNumEntries());
163  if (i == 0)
164  lev0Nnz = totalNnz;
165  }
166  return totalNnz / lev0Nnz;
167 }
168 
169 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
171  double node_sc = 0, global_sc = 0;
172  double a0_nnz = 0;
173  const size_t INVALID = Teuchos::OrdinalTraits<size_t>::invalid();
174  // Get cost of fine matvec
175  if (GetNumLevels() <= 0) return -1.0;
176  if (!Levels_[0]->IsAvailable("A")) return -1.0;
177 
178  RCP<Operator> A = Levels_[0]->template Get<RCP<Operator>>("A");
179  if (A.is_null()) return -1.0;
180  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
181  if (Am.is_null()) return -1.0;
182  a0_nnz = as<double>(Am->getGlobalNumEntries());
183 
184  // Get smoother complexity at each level
185  for (int i = 0; i < GetNumLevels(); ++i) {
186  size_t level_sc = 0;
187  if (!Levels_[i]->IsAvailable("PreSmoother")) continue;
188  RCP<SmootherBase> S = Levels_[i]->template Get<RCP<SmootherBase>>("PreSmoother");
189  if (S.is_null()) continue;
190  level_sc = S->getNodeSmootherComplexity();
191  if (level_sc == INVALID) {
192  global_sc = -1.0;
193  break;
194  }
195 
196  node_sc += as<double>(level_sc);
197  }
198 
199  double min_sc = 0.0;
200  RCP<const Teuchos::Comm<int>> comm = A->getDomainMap()->getComm();
201  Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, node_sc, Teuchos::ptr(&global_sc));
202  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MIN, node_sc, Teuchos::ptr(&min_sc));
203 
204  if (min_sc < 0.0)
205  return -1.0;
206  else
207  return global_sc / a0_nnz;
208 }
209 
210 // Coherence checks todo in Setup() (using an helper function):
211 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
214  "MueLu::Hierarchy::CheckLevel(): wrong underlying linear algebra library.");
215  TEUCHOS_TEST_FOR_EXCEPTION(level.GetLevelID() != levelID, Exceptions::RuntimeError,
216  "MueLu::Hierarchy::CheckLevel(): wrong level ID");
217  TEUCHOS_TEST_FOR_EXCEPTION(levelID != 0 && level.GetPreviousLevel() != Levels_[levelID - 1], Exceptions::RuntimeError,
218  "MueLu::Hierarchy::Setup(): wrong level parent");
219 }
220 
221 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
223  for (int i = 0; i < GetNumLevels(); ++i) {
224  RCP<Level> level = Levels_[i];
225  if (level->IsAvailable("A")) {
226  RCP<Operator> Aop = level->Get<RCP<Operator>>("A");
227  RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Aop);
228  if (!A.is_null()) {
229  RCP<const Import> xpImporter = A->getCrsGraph()->getImporter();
230  if (!xpImporter.is_null())
231  xpImporter->setDistributorParameters(matvecParams);
232  RCP<const Export> xpExporter = A->getCrsGraph()->getExporter();
233  if (!xpExporter.is_null())
234  xpExporter->setDistributorParameters(matvecParams);
235  }
236  }
237  if (level->IsAvailable("P")) {
238  RCP<Matrix> P = level->Get<RCP<Matrix>>("P");
239  RCP<const Import> xpImporter = P->getCrsGraph()->getImporter();
240  if (!xpImporter.is_null())
241  xpImporter->setDistributorParameters(matvecParams);
242  RCP<const Export> xpExporter = P->getCrsGraph()->getExporter();
243  if (!xpExporter.is_null())
244  xpExporter->setDistributorParameters(matvecParams);
245  }
246  if (level->IsAvailable("R")) {
247  RCP<Matrix> R = level->Get<RCP<Matrix>>("R");
248  RCP<const Import> xpImporter = R->getCrsGraph()->getImporter();
249  if (!xpImporter.is_null())
250  xpImporter->setDistributorParameters(matvecParams);
251  RCP<const Export> xpExporter = R->getCrsGraph()->getExporter();
252  if (!xpExporter.is_null())
253  xpExporter->setDistributorParameters(matvecParams);
254  }
255  if (level->IsAvailable("Importer")) {
256  RCP<const Import> xpImporter = level->Get<RCP<const Import>>("Importer");
257  if (!xpImporter.is_null())
258  xpImporter->setDistributorParameters(matvecParams);
259  }
260  }
261 }
262 
263 // The function uses three managers: fine, coarse and next coarse
264 // We construct the data for the coarse level, and do requests for the next coarse
265 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
267  const RCP<const FactoryManagerBase> fineLevelManager,
268  const RCP<const FactoryManagerBase> coarseLevelManager,
269  const RCP<const FactoryManagerBase> nextLevelManager) {
270  // Use PrintMonitor/TimerMonitor instead of just a FactoryMonitor to print "Level 0" instead of Hierarchy(0)
271  // Print is done after the requests for next coarse level
272 
273  TEUCHOS_TEST_FOR_EXCEPTION(LastLevelID() < coarseLevelID, Exceptions::RuntimeError,
274  "MueLu::Hierarchy:Setup(): level " << coarseLevelID << " (specified by coarseLevelID argument) "
275  "must be built before calling this function.");
276 
277  Level& level = *Levels_[coarseLevelID];
278 
279  bool useStackedTimer = !Teuchos::TimeMonitor::stackedTimerNameIsDefault();
280 
281  std::string label = FormattingHelper::getColonLabel(level.getObjectLabel());
282  RCP<TimeMonitor> m1;
283  if (!useStackedTimer)
284  m1 = rcp(new TimeMonitor(*this, label + this->ShortClassName() + ": " + "Setup (total)"));
285  TimeMonitor m2(*this, label + this->ShortClassName() + ": " + "Setup" + " (total, level=" + Teuchos::toString(coarseLevelID) + ")");
286 
287  // TODO: pass coarseLevelManager by reference
288  TEUCHOS_TEST_FOR_EXCEPTION(coarseLevelManager == Teuchos::null, Exceptions::RuntimeError,
289  "MueLu::Hierarchy::Setup(): argument coarseLevelManager cannot be null");
290 
293 
294  if (levelManagers_.size() < coarseLevelID + 1)
295  levelManagers_.resize(coarseLevelID + 1);
296  levelManagers_[coarseLevelID] = coarseLevelManager;
297 
298  bool isFinestLevel = (fineLevelManager.is_null());
299  bool isLastLevel = (nextLevelManager.is_null());
300 
301  int oldRank = -1;
302  if (isFinestLevel) {
303  RCP<Operator> A = level.Get<RCP<Operator>>("A");
304  RCP<const Map> domainMap = A->getDomainMap();
305  RCP<const Teuchos::Comm<int>> comm = domainMap->getComm();
306 
307  // Initialize random seed for reproducibility
309 
310  // Record the communicator on the level (used for timers sync)
311  level.SetComm(comm);
312  oldRank = SetProcRankVerbose(comm->getRank());
313 
314  // Set the Hierarchy library to match that of the finest level matrix,
315  // even if it was already set
316  lib_ = domainMap->lib();
317  level.setlib(lib_);
318 
319  } else {
320  // Permeate library to a coarser level
321  level.setlib(lib_);
322 
323  Level& prevLevel = *Levels_[coarseLevelID - 1];
324  oldRank = SetProcRankVerbose(prevLevel.GetComm()->getRank());
325  }
326 
327  CheckLevel(level, coarseLevelID);
328 
329  // Attach FactoryManager to the fine level
330  RCP<SetFactoryManager> SFMFine;
331  if (!isFinestLevel)
332  SFMFine = rcp(new SetFactoryManager(Levels_[coarseLevelID - 1], fineLevelManager));
333 
334  if (isFinestLevel && Levels_[coarseLevelID]->IsAvailable("Coordinates"))
335  ReplaceCoordinateMap(*Levels_[coarseLevelID]);
336 
337  // Attach FactoryManager to the coarse level
338  SetFactoryManager SFMCoarse(Levels_[coarseLevelID], coarseLevelManager);
339 
340  if (isDumpingEnabled_ && (dumpLevel_ == 0 || dumpLevel_ == -1) && coarseLevelID == 1)
341  DumpCurrentGraph(0);
342 
343  RCP<TopSmootherFactory> coarseFact;
344  RCP<TopSmootherFactory> smootherFact = rcp(new TopSmootherFactory(coarseLevelManager, "Smoother"));
345 
346  int nextLevelID = coarseLevelID + 1;
347 
348  RCP<SetFactoryManager> SFMNext;
349  if (isLastLevel == false) {
350  // We are not at the coarsest level, so there is going to be another level ("next coarse") after this one ("coarse")
351  if (nextLevelID > LastLevelID())
352  AddNewLevel();
353  CheckLevel(*Levels_[nextLevelID], nextLevelID);
354 
355  // Attach FactoryManager to the next level (level after coarse)
356  SFMNext = rcp(new SetFactoryManager(Levels_[nextLevelID], nextLevelManager));
357  Levels_[nextLevelID]->Request(TopRAPFactory(coarseLevelManager, nextLevelManager));
358 
359  // Do smoother requests here. We don't know whether this is going to be
360  // the coarsest level or not, but we need to DeclareInput before we call
361  // coarseRAPFactory.Build(), otherwise some stuff may be erased after
362  // level releases
363  level.Request(*smootherFact);
364 
365  } else {
366  // Similar to smoother above, do the coarse solver request here. We don't
367  // know whether this is going to be the coarsest level or not, but we
368  // need to DeclareInput before we call coarseRAPFactory.Build(),
369  // otherwise some stuff may be erased after level releases. This is
370  // actually evident on ProjectorSmoother. It requires both "A" and
371  // "Nullspace". However, "Nullspace" is erased after all releases, so if
372  // we call the coarse factory request after RAP build we would not have
373  // any data, and cannot get it as we don't have previous managers. The
374  // typical trace looks like this:
375  //
376  // MueLu::Level(0)::GetFactory(Aggregates, 0): No FactoryManager
377  // during request for data " Aggregates" on level 0 by factory TentativePFactory
378  // during request for data " P" on level 1 by factory EminPFactory
379  // during request for data " P" on level 1 by factory TransPFactory
380  // during request for data " R" on level 1 by factory RAPFactory
381  // during request for data " A" on level 1 by factory TentativePFactory
382  // during request for data " Nullspace" on level 2 by factory NullspaceFactory
383  // during request for data " Nullspace" on level 2 by factory NullspacePresmoothFactory
384  // during request for data " Nullspace" on level 2 by factory ProjectorSmoother
385  // during request for data " PreSmoother" on level 2 by factory NoFactory
386  if (coarseFact.is_null())
387  coarseFact = rcp(new TopSmootherFactory(coarseLevelManager, "CoarseSolver"));
388  level.Request(*coarseFact);
389  }
390 
391  GetOStream(Runtime0) << std::endl;
392  PrintMonitor m0(*this, "Level " + Teuchos::toString(coarseLevelID), static_cast<MsgType>(Runtime0 | Test));
393 
394  // Build coarse level hierarchy
395  RCP<Operator> Ac = Teuchos::null;
396  TopRAPFactory coarseRAPFactory(fineLevelManager, coarseLevelManager);
397 
398  if (level.IsAvailable("A")) {
399  Ac = level.Get<RCP<Operator>>("A");
400  } else if (!isFinestLevel) {
401  // We only build here, the release is done later
402  coarseRAPFactory.Build(*level.GetPreviousLevel(), level);
403  }
404 
405  bool setLastLevelviaMaxCoarseSize = false;
406  if (level.IsAvailable("A"))
407  Ac = level.Get<RCP<Operator>>("A");
408  RCP<Matrix> Acm = rcp_dynamic_cast<Matrix>(Ac);
409 
410  // Record the communicator on the level
411  if (!Ac.is_null())
412  level.SetComm(Ac->getDomainMap()->getComm());
413 
414  // Test if we reach the end of the hierarchy
415  bool isOrigLastLevel = isLastLevel;
416  if (isLastLevel) {
417  // Last level as we have achieved the max limit
418  isLastLevel = true;
419 
420  } else if (Ac.is_null()) {
421  // Last level for this processor, as it does not belong to the next
422  // subcommunicator. Other processors may continue working on the
423  // hierarchy
424  isLastLevel = true;
425 
426  } else {
427  if (!Acm.is_null() && Acm->getGlobalNumRows() <= maxCoarseSize_) {
428  // Last level as the size of the coarse matrix became too small
429  GetOStream(Runtime0) << "Max coarse size (<= " << maxCoarseSize_ << ") achieved" << std::endl;
430  isLastLevel = true;
431  if (Acm->getGlobalNumRows() != 0) setLastLevelviaMaxCoarseSize = true;
432  }
433  }
434 
435  if (!Ac.is_null() && !isFinestLevel) {
436  RCP<Operator> A = Levels_[coarseLevelID - 1]->template Get<RCP<Operator>>("A");
437  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
438 
439  const double maxCoarse2FineRatio = 0.8;
440  if (!Acm.is_null() && !Am.is_null() && Acm->getGlobalNumRows() > maxCoarse2FineRatio * Am->getGlobalNumRows()) {
441  // We could abort here, but for now we simply notify user.
442  // Couple of additional points:
443  // - if repartitioning is delayed until level K, but the aggregation
444  // procedure stagnates between levels K-1 and K. In this case,
445  // repartitioning could enable faster coarsening once again, but the
446  // hierarchy construction will abort due to the stagnation check.
447  // - if the matrix is small enough, we could move it to one processor.
448  GetOStream(Warnings0) << "Aggregation stagnated. Please check your matrix and/or adjust your configuration file."
449  << "Possible fixes:\n"
450  << " - reduce the maximum number of levels\n"
451  << " - enable repartitioning\n"
452  << " - increase the minimum coarse size." << std::endl;
453  }
454  }
455 
456  if (isLastLevel) {
457  if (!isOrigLastLevel) {
458  // We did not expect to finish this early so we did request a smoother.
459  // We need a coarse solver instead. Do the magic.
460  level.Release(*smootherFact);
461  if (coarseFact.is_null())
462  coarseFact = rcp(new TopSmootherFactory(coarseLevelManager, "CoarseSolver"));
463  level.Request(*coarseFact);
464  }
465 
466  // Do the actual build, if we have any data.
467  // NOTE: this is not a great check, we may want to call Build() regardless.
468  if (!Ac.is_null())
469  coarseFact->Build(level);
470 
471  // Once the dirty deed is done, release stuff. The smoother has already
472  // been released.
473  level.Release(*coarseFact);
474 
475  } else {
476  // isLastLevel = false => isOrigLastLevel = false, meaning that we have
477  // requested the smoother. Now we need to build it and to release it.
478  // We don't need to worry about the coarse solver, as we didn't request it.
479  if (!Ac.is_null())
480  smootherFact->Build(level);
481 
482  level.Release(*smootherFact);
483  }
484 
485  if (isLastLevel == true) {
486  int actualNumLevels = nextLevelID;
487  if (isOrigLastLevel == false) {
488  // Earlier in the function, we constructed the next coarse level, and requested data for the that level,
489  // assuming that we are not at the coarsest level. Now, we changed our mind, so we have to release those.
490  Levels_[nextLevelID]->Release(TopRAPFactory(coarseLevelManager, nextLevelManager));
491 
492  // We truncate/resize the hierarchy and possibly remove the last created level if there is
493  // something wrong with it as indicated by its P not being valid. This might happen
494  // if the global number of aggregates turns out to be zero
495 
496  if (!setLastLevelviaMaxCoarseSize) {
497  if (Levels_[nextLevelID - 1]->IsAvailable("P")) {
498  if (Levels_[nextLevelID - 1]->template Get<RCP<Matrix>>("P") == Teuchos::null) actualNumLevels = nextLevelID - 1;
499  } else
500  actualNumLevels = nextLevelID - 1;
501  }
502  }
503  if (actualNumLevels == nextLevelID - 1) {
504  // Didn't expect to finish early so we requested smoother but need coarse solver instead.
505  Levels_[nextLevelID - 2]->Release(*smootherFact);
506 
507  if (Levels_[nextLevelID - 2]->IsAvailable("PreSmoother")) Levels_[nextLevelID - 2]->RemoveKeepFlag("PreSmoother", NoFactory::get());
508  if (Levels_[nextLevelID - 2]->IsAvailable("PostSmoother")) Levels_[nextLevelID - 2]->RemoveKeepFlag("PostSmoother", NoFactory::get());
509  if (coarseFact.is_null())
510  coarseFact = rcp(new TopSmootherFactory(coarseLevelManager, "CoarseSolver"));
511  Levels_[nextLevelID - 2]->Request(*coarseFact);
512  if (!(Levels_[nextLevelID - 2]->template Get<RCP<Matrix>>("A").is_null()))
513  coarseFact->Build(*(Levels_[nextLevelID - 2]));
514  Levels_[nextLevelID - 2]->Release(*coarseFact);
515  }
516  Levels_.resize(actualNumLevels);
517  }
518 
519  // I think this is the proper place for graph so that it shows every dependence
520  if (isDumpingEnabled_ && ((dumpLevel_ > 0 && coarseLevelID == dumpLevel_) || dumpLevel_ == -1))
521  DumpCurrentGraph(coarseLevelID);
522 
523  if (!isFinestLevel) {
524  // Release the hierarchy data
525  // We release so late to help blocked solvers, as the smoothers for them need A blocks
526  // which we construct in RAPFactory
527  level.Release(coarseRAPFactory);
528  }
529 
530  if (oldRank != -1)
531  SetProcRankVerbose(oldRank);
532 
533  return isLastLevel;
534 }
535 
536 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
538  int numLevels = Levels_.size();
539  TEUCHOS_TEST_FOR_EXCEPTION(levelManagers_.size() != numLevels, Exceptions::RuntimeError,
540  "Hierarchy::SetupRe: " << Levels_.size() << " levels, but " << levelManagers_.size() << " level factory managers");
541 
542  const int startLevel = 0;
543  Clear(startLevel);
544 
545 #ifdef HAVE_MUELU_DEBUG
546  // Reset factories' data used for debugging
547  for (int i = 0; i < numLevels; i++)
548  levelManagers_[i]->ResetDebugData();
549 
550 #endif
551 
552  int levelID;
553  for (levelID = startLevel; levelID < numLevels;) {
554  bool r = Setup(levelID,
555  (levelID != 0 ? levelManagers_[levelID - 1] : Teuchos::null),
556  levelManagers_[levelID],
557  (levelID + 1 != numLevels ? levelManagers_[levelID + 1] : Teuchos::null));
558  levelID++;
559  if (r) break;
560  }
561  // We may construct fewer levels for some reason, make sure we continue
562  // doing that in the future
563  Levels_.resize(levelID);
564  levelManagers_.resize(levelID);
565 
566  int sizeOfVecs = sizeOfAllocatedLevelMultiVectors_;
567 
568  AllocateLevelMultiVectors(sizeOfVecs, true);
569 
570  // since the # of levels, etc. may have changed, force re-determination of description during next call to description()
571  ResetDescription();
572 
573  describe(GetOStream(Statistics0), GetVerbLevel());
574 
575  CheckForEmptySmoothersAndCoarseSolve();
576 }
577 
578 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
579 void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Setup(const FactoryManagerBase& manager, int startLevel, int numDesiredLevels) {
580  // Use MueLu::BaseClass::description() to avoid printing "{numLevels = 1}" (numLevels is increasing...)
581  PrintMonitor m0(*this, "Setup (" + this->MueLu::BaseClass::description() + ")", Runtime0);
582 
583  Clear(startLevel);
584 
585  // Check Levels_[startLevel] exists.
586  TEUCHOS_TEST_FOR_EXCEPTION(Levels_.size() <= startLevel, Exceptions::RuntimeError,
587  "MueLu::Hierarchy::Setup(): fine level (" << startLevel << ") does not exist");
588 
589  TEUCHOS_TEST_FOR_EXCEPTION(numDesiredLevels <= 0, Exceptions::RuntimeError,
590  "Constructing non-positive (" << numDesiredLevels << ") number of levels does not make sense.");
591 
592  // Check for fine level matrix A
593  TEUCHOS_TEST_FOR_EXCEPTION(!Levels_[startLevel]->IsAvailable("A"), Exceptions::RuntimeError,
594  "MueLu::Hierarchy::Setup(): fine level (" << startLevel << ") has no matrix A! "
595  "Set fine level matrix A using Level.Set()");
596 
597  RCP<Operator> A = Levels_[startLevel]->template Get<RCP<Operator>>("A");
598  lib_ = A->getDomainMap()->lib();
599 
600  if (IsPrint(Statistics2)) {
601  RCP<Matrix> Amat = rcp_dynamic_cast<Matrix>(A);
602 
603  if (!Amat.is_null()) {
604  RCP<ParameterList> params = rcp(new ParameterList());
605  params->set("printLoadBalancingInfo", true);
606  params->set("printCommInfo", true);
607 
608  GetOStream(Statistics2) << PerfUtils::PrintMatrixInfo(*Amat, "A0", params);
609  } else {
610  GetOStream(Warnings1) << "Fine level operator is not a matrix, statistics are not available" << std::endl;
611  }
612  }
613 
614  RCP<const FactoryManagerBase> rcpmanager = rcpFromRef(manager);
615 
616  const int lastLevel = startLevel + numDesiredLevels - 1;
617  GetOStream(Runtime0) << "Setup loop: startLevel = " << startLevel << ", lastLevel = " << lastLevel
618  << " (stop if numLevels = " << numDesiredLevels << " or Ac.size() < " << maxCoarseSize_ << ")" << std::endl;
619 
620  // Setup multigrid levels
621  int iLevel = 0;
622  if (numDesiredLevels == 1) {
623  iLevel = 0;
624  Setup(startLevel, Teuchos::null, rcpmanager, Teuchos::null); // setup finest==coarsest level (first and last managers are Teuchos::null)
625 
626  } else {
627  bool bIsLastLevel = Setup(startLevel, Teuchos::null, rcpmanager, rcpmanager); // setup finest level (level 0) (first manager is Teuchos::null)
628  if (bIsLastLevel == false) {
629  for (iLevel = startLevel + 1; iLevel < lastLevel; iLevel++) {
630  bIsLastLevel = Setup(iLevel, rcpmanager, rcpmanager, rcpmanager); // setup intermediate levels
631  if (bIsLastLevel == true)
632  break;
633  }
634  if (bIsLastLevel == false)
635  Setup(lastLevel, rcpmanager, rcpmanager, Teuchos::null); // setup coarsest level (last manager is Teuchos::null)
636  }
637  }
638 
639  // TODO: some check like this should be done at the beginning of the routine
640  TEUCHOS_TEST_FOR_EXCEPTION(iLevel != Levels_.size() - 1, Exceptions::RuntimeError,
641  "MueLu::Hierarchy::Setup(): number of level");
642 
643  // TODO: this is not exception safe: manager will still hold default
644  // factories if you exit this function with an exception
645  manager.Clean();
646 
647  describe(GetOStream(Statistics0), GetVerbLevel());
648 
649  CheckForEmptySmoothersAndCoarseSolve();
650 }
651 
652 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
654  for (LO levelNo = 0; levelNo < GetNumLevels(); ++levelNo) {
655  auto level = Levels_[levelNo];
656  if ((level->IsAvailable("A") && !level->template Get<RCP<Operator>>("A").is_null()) && (!level->IsAvailable("PreSmoother")) && (!level->IsAvailable("PostSmoother"))) {
657  GetOStream(Warnings1) << "No " << (levelNo == as<LO>(Levels_.size()) - 1 ? "coarse grid solver" : "smoother") << " on level " << level->GetLevelID() << std::endl;
658  }
659  }
660 }
661 
662 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
664  if (startLevel < GetNumLevels())
665  GetOStream(Runtime0) << "Clearing old data (if any)" << std::endl;
666 
667  for (int iLevel = startLevel; iLevel < GetNumLevels(); iLevel++)
668  Levels_[iLevel]->Clear();
669 }
670 
671 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
673  GetOStream(Runtime0) << "Clearing old data (expert)" << std::endl;
674  for (int iLevel = 0; iLevel < GetNumLevels(); iLevel++)
675  Levels_[iLevel]->ExpertClear();
676 }
677 
678 #if defined(HAVE_MUELU_EXPERIMENTAL) && defined(HAVE_MUELU_ADDITIVE_VARIANT)
679 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
680 ConvergenceStatus Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Iterate(const MultiVector& B, MultiVector& X, ConvData conv,
681  bool InitialGuessIsZero, LO startLevel) {
682  LO nIts = conv.maxIts_;
683  MagnitudeType tol = conv.tol_;
684 
685  std::string prefix = this->ShortClassName() + ": ";
686  std::string levelSuffix = " (level=" + toString(startLevel) + ")";
687  std::string levelSuffix1 = " (level=" + toString(startLevel + 1) + ")";
688 
689  using namespace Teuchos;
690  RCP<Time> CompTime = Teuchos::TimeMonitor::getNewCounter(prefix + "Computational Time (total)");
691  RCP<Time> Concurrent = Teuchos::TimeMonitor::getNewCounter(prefix + "Concurrent portion");
692  RCP<Time> ApplyR = Teuchos::TimeMonitor::getNewCounter(prefix + "R: Computational Time");
693  RCP<Time> ApplyPbar = Teuchos::TimeMonitor::getNewCounter(prefix + "Pbar: Computational Time");
694  RCP<Time> CompFine = Teuchos::TimeMonitor::getNewCounter(prefix + "Fine: Computational Time");
695  RCP<Time> CompCoarse = Teuchos::TimeMonitor::getNewCounter(prefix + "Coarse: Computational Time");
696  RCP<Time> ApplySum = Teuchos::TimeMonitor::getNewCounter(prefix + "Sum: Computational Time");
697  RCP<Time> Synchronize_beginning = Teuchos::TimeMonitor::getNewCounter(prefix + "Synchronize_beginning");
698  RCP<Time> Synchronize_center = Teuchos::TimeMonitor::getNewCounter(prefix + "Synchronize_center");
699  RCP<Time> Synchronize_end = Teuchos::TimeMonitor::getNewCounter(prefix + "Synchronize_end");
700 
701  RCP<Level> Fine = Levels_[0];
702  RCP<Level> Coarse;
703 
704  RCP<Operator> A = Fine->Get<RCP<Operator>>("A");
705  Teuchos::RCP<const Teuchos::Comm<int>> communicator = A->getDomainMap()->getComm();
706 
707  // Synchronize_beginning->start();
708  // communicator->barrier();
709  // Synchronize_beginning->stop();
710 
711  CompTime->start();
712 
713  SC one = STS::one(), zero = STS::zero();
714 
715  bool zeroGuess = InitialGuessIsZero;
716 
717  // ======= UPFRONT DEFINITION OF COARSE VARIABLES ===========
718 
719  // RCP<const Map> origMap;
720  RCP<Operator> P;
721  RCP<Operator> Pbar;
722  RCP<Operator> R;
723  RCP<MultiVector> coarseRhs, coarseX;
724  RCP<Operator> Ac;
725  RCP<SmootherBase> preSmoo_coarse, postSmoo_coarse;
726  bool emptyCoarseSolve = true;
727  RCP<MultiVector> coarseX_prolonged = MultiVectorFactory::Build(X.getMap(), X.getNumVectors(), true);
728 
729  RCP<const Import> importer;
730 
731  if (Levels_.size() > 1) {
732  Coarse = Levels_[1];
733  if (Coarse->IsAvailable("Importer"))
734  importer = Coarse->Get<RCP<const Import>>("Importer");
735 
736  R = Coarse->Get<RCP<Operator>>("R");
737  P = Coarse->Get<RCP<Operator>>("P");
738 
739  // if(Coarse->IsAvailable("Pbar"))
740  Pbar = Coarse->Get<RCP<Operator>>("Pbar");
741 
742  coarseRhs = MultiVectorFactory::Build(R->getRangeMap(), B.getNumVectors(), true);
743 
744  Ac = Coarse->Get<RCP<Operator>>("A");
745 
746  ApplyR->start();
747  R->apply(B, *coarseRhs, Teuchos::NO_TRANS, one, zero);
748  // P->apply(B, *coarseRhs, Teuchos::TRANS, one, zero);
749  ApplyR->stop();
750 
751  if (doPRrebalance_ || importer.is_null()) {
752  coarseX = MultiVectorFactory::Build(coarseRhs->getMap(), X.getNumVectors(), true);
753 
754  } else {
755  RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : import (total)", Timings0));
756  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : import" + levelSuffix1, Timings0));
757 
758  // Import: range map of R --> domain map of rebalanced Ac (before subcomm replacement)
759  RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getTargetMap(), coarseRhs->getNumVectors());
760  coarseTmp->doImport(*coarseRhs, *importer, Xpetra::INSERT);
761  coarseRhs.swap(coarseTmp);
762 
763  coarseX = MultiVectorFactory::Build(importer->getTargetMap(), X.getNumVectors(), true);
764  }
765 
766  if (Coarse->IsAvailable("PreSmoother"))
767  preSmoo_coarse = Coarse->Get<RCP<SmootherBase>>("PreSmoother");
768  if (Coarse->IsAvailable("PostSmoother"))
769  postSmoo_coarse = Coarse->Get<RCP<SmootherBase>>("PostSmoother");
770  }
771 
772  // ==========================================================
773 
774  MagnitudeType prevNorm = STS::magnitude(STS::one()), curNorm = STS::magnitude(STS::one());
775  rate_ = 1.0;
776 
777  for (LO i = 1; i <= nIts; i++) {
778 #ifdef HAVE_MUELU_DEBUG
779  if (A->getDomainMap()->isCompatible(*(X.getMap())) == false) {
780  std::ostringstream ss;
781  ss << "Level " << startLevel << ": level A's domain map is not compatible with X";
782  throw Exceptions::Incompatible(ss.str());
783  }
784 
785  if (A->getRangeMap()->isCompatible(*(B.getMap())) == false) {
786  std::ostringstream ss;
787  ss << "Level " << startLevel << ": level A's range map is not compatible with B";
788  throw Exceptions::Incompatible(ss.str());
789  }
790 #endif
791  }
792 
793  bool emptyFineSolve = true;
794 
795  RCP<MultiVector> fineX;
796  fineX = MultiVectorFactory::Build(X.getMap(), X.getNumVectors(), true);
797 
798  // Synchronize_center->start();
799  // communicator->barrier();
800  // Synchronize_center->stop();
801 
802  Concurrent->start();
803 
804  // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
805  if (Fine->IsAvailable("PreSmoother")) {
806  RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
807  CompFine->start();
808  preSmoo->Apply(*fineX, B, zeroGuess);
809  CompFine->stop();
810  emptyFineSolve = false;
811  }
812  if (Fine->IsAvailable("PostSmoother")) {
813  RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
814  CompFine->start();
815  postSmoo->Apply(*fineX, B, zeroGuess);
816  CompFine->stop();
817 
818  emptyFineSolve = false;
819  }
820  if (emptyFineSolve == true) {
821  // Fine grid smoother is identity
822  fineX->update(one, B, zero);
823  }
824 
825  if (Levels_.size() > 1) {
826  // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
827  if (Coarse->IsAvailable("PreSmoother")) {
828  CompCoarse->start();
829  preSmoo_coarse->Apply(*coarseX, *coarseRhs, zeroGuess);
830  CompCoarse->stop();
831  emptyCoarseSolve = false;
832  }
833  if (Coarse->IsAvailable("PostSmoother")) {
834  CompCoarse->start();
835  postSmoo_coarse->Apply(*coarseX, *coarseRhs, zeroGuess);
836  CompCoarse->stop();
837  emptyCoarseSolve = false;
838  }
839  if (emptyCoarseSolve == true) {
840  // Coarse operator is identity
841  coarseX->update(one, *coarseRhs, zero);
842  }
843  Concurrent->stop();
844  // Synchronize_end->start();
845  // communicator->barrier();
846  // Synchronize_end->stop();
847 
848  if (!doPRrebalance_ && !importer.is_null()) {
849  RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : export (total)", Timings0));
850  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : export" + levelSuffix1, Timings0));
851 
852  // Import: range map of rebalanced Ac (before subcomm replacement) --> domain map of P
853  RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getSourceMap(), coarseX->getNumVectors());
854  coarseTmp->doExport(*coarseX, *importer, Xpetra::INSERT);
855  coarseX.swap(coarseTmp);
856  }
857 
858  ApplyPbar->start();
859  Pbar->apply(*coarseX, *coarseX_prolonged, Teuchos::NO_TRANS, one, zero);
860  ApplyPbar->stop();
861  }
862 
863  ApplySum->start();
864  X.update(1.0, *fineX, 1.0, *coarseX_prolonged, 0.0);
865  ApplySum->stop();
866 
867  CompTime->stop();
868 
869  // communicator->barrier();
870 
872 }
873 #else
874 // ---------------------------------------- Iterate -------------------------------------------------------
875 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
877  bool InitialGuessIsZero, LO startLevel) {
878  LO nIts = conv.maxIts_;
879  MagnitudeType tol = conv.tol_;
880 
881  // These timers work as follows. "iterateTime" records total time spent in
882  // iterate. "levelTime" records time on a per level basis. The label is
883  // crafted to mimic the per-level messages used in Monitors. Note that a
884  // given level is timed with a TimeMonitor instead of a Monitor or
885  // SubMonitor. This is mainly because I want to time each level
886  // separately, and Monitors/SubMonitors print "(total) xx yy zz" ,
887  // "(sub,total) xx yy zz", respectively, which is subject to
888  // misinterpretation. The per-level TimeMonitors are stopped/started
889  // manually before/after a recursive call to Iterate. A side artifact to
890  // this approach is that the counts for intermediate level timers are twice
891  // the counts for the finest and coarsest levels.
892 
893  RCP<Level> Fine = Levels_[startLevel];
894 
895  std::string label = FormattingHelper::getColonLabel(Fine->getObjectLabel());
896  std::string prefix = label + this->ShortClassName() + ": ";
897  std::string levelSuffix = " (level=" + toString(startLevel) + ")";
898  std::string levelSuffix1 = " (level=" + toString(startLevel + 1) + ")";
899 
900  bool useStackedTimer = !Teuchos::TimeMonitor::stackedTimerNameIsDefault();
901 
902  RCP<Monitor> iterateTime;
903  RCP<TimeMonitor> iterateTime1;
904  if (startLevel == 0)
905  iterateTime = rcp(new Monitor(*this, "Solve", label, (nIts == 1) ? None : Runtime0, Timings0));
906  else if (!useStackedTimer)
907  iterateTime1 = rcp(new TimeMonitor(*this, prefix + "Solve (total, level=" + toString(startLevel) + ")", Timings0));
908 
909  std::string iterateLevelTimeLabel = prefix + "Solve" + levelSuffix;
910  RCP<TimeMonitor> iterateLevelTime = rcp(new TimeMonitor(*this, iterateLevelTimeLabel, Timings0));
911 
912  bool zeroGuess = InitialGuessIsZero;
913 
914  RCP<Operator> A = Fine->Get<RCP<Operator>>("A");
915  using namespace Teuchos;
916  RCP<Time> CompCoarse = Teuchos::TimeMonitor::getNewCounter(prefix + "Coarse: Computational Time");
917 
918  if (A.is_null()) {
919  // This processor does not have any data for this process on coarser
920  // levels. This can only happen when there are multiple processors and
921  // we use repartitioning.
923  }
924 
925  // If we switched the number of vectors, we'd need to reallocate here.
926  // If the number of vectors is unchanged, this is a noop.
927  // NOTE: We need to check against B because the tests in AllocateLevelMultiVectors
928  // will fail on Stokhos Scalar types (due to the so-called 'hidden dimension')
929  const BlockedMultiVector* Bblocked = dynamic_cast<const BlockedMultiVector*>(&B);
930  if (residual_.size() > startLevel &&
931  ((Bblocked && !Bblocked->isSameSize(*residual_[startLevel])) ||
932  (!Bblocked && !residual_[startLevel]->isSameSize(B))))
933  DeleteLevelMultiVectors();
934  AllocateLevelMultiVectors(X.getNumVectors());
935 
936  // Print residual information before iterating
938  MagnitudeType prevNorm = STM::one();
939  rate_ = 1.0;
940  if (IsCalculationOfResidualRequired(startLevel, conv)) {
941  ConvergenceStatus convergenceStatus = ComputeResidualAndPrintHistory(*A, X, B, Teuchos::ScalarTraits<LO>::zero(), startLevel, conv, prevNorm);
942  if (convergenceStatus == MueLu::ConvergenceStatus::Converged)
943  return convergenceStatus;
944  }
945 
946  SC one = STS::one(), zero = STS::zero();
947  for (LO iteration = 1; iteration <= nIts; iteration++) {
948 #ifdef HAVE_MUELU_DEBUG
949 #if 0 // TODO fix me
950  if (A->getDomainMap()->isCompatible(*(X.getMap())) == false) {
951  std::ostringstream ss;
952  ss << "Level " << startLevel << ": level A's domain map is not compatible with X";
953  throw Exceptions::Incompatible(ss.str());
954  }
955 
956  if (A->getRangeMap()->isCompatible(*(B.getMap())) == false) {
957  std::ostringstream ss;
958  ss << "Level " << startLevel << ": level A's range map is not compatible with B";
959  throw Exceptions::Incompatible(ss.str());
960  }
961 #endif
962 #endif
963 
964  if (startLevel == as<LO>(Levels_.size()) - 1) {
965  // On the coarsest level, we do either smoothing (if defined) or a direct solve.
966  RCP<TimeMonitor> CLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : coarse" + levelSuffix, Timings0));
967 
968  bool emptySolve = true;
969 
970  // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
971  if (Fine->IsAvailable("PreSmoother")) {
972  RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
973  CompCoarse->start();
974  preSmoo->Apply(X, B, zeroGuess);
975  CompCoarse->stop();
976  zeroGuess = false;
977  emptySolve = false;
978  }
979  if (Fine->IsAvailable("PostSmoother")) {
980  RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
981  CompCoarse->start();
982  postSmoo->Apply(X, B, zeroGuess);
983  CompCoarse->stop();
984  emptySolve = false;
985  zeroGuess = false;
986  }
987  if (emptySolve == true) {
988  // Coarse operator is identity
989  X.update(one, B, zero);
990  }
991 
992  } else {
993  // On intermediate levels, we do cycles
994  RCP<Level> Coarse = Levels_[startLevel + 1];
995  {
996  // ============== PRESMOOTHING ==============
997  RCP<TimeMonitor> STime;
998  if (!useStackedTimer)
999  STime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing (total)", Timings0));
1000  RCP<TimeMonitor> SLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing" + levelSuffix, Timings0));
1001 
1002  if (Fine->IsAvailable("PreSmoother")) {
1003  RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
1004  preSmoo->Apply(X, B, zeroGuess);
1005  zeroGuess = false;
1006  }
1007  }
1008 
1010  {
1011  RCP<TimeMonitor> ATime;
1012  if (!useStackedTimer)
1013  ATime = rcp(new TimeMonitor(*this, prefix + "Solve : residual calculation (total)", Timings0));
1014  RCP<TimeMonitor> ALevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : residual calculation" + levelSuffix, Timings0));
1015  if (zeroGuess) {
1016  // If there's a pre-smoother, then zeroGuess is false. If there isn't and people still have zeroGuess set,
1017  // then then X still has who knows what, so we need to zero it before we go to the coarse grid.
1018  X.putScalar(zero);
1019  }
1020 
1021  Utilities::Residual(*A, X, B, *residual_[startLevel]);
1022  residual = residual_[startLevel];
1023  }
1024 
1025  RCP<Operator> P = Coarse->Get<RCP<Operator>>("P");
1026  if (Coarse->IsAvailable("Pbar"))
1027  P = Coarse->Get<RCP<Operator>>("Pbar");
1028 
1029  RCP<MultiVector> coarseRhs, coarseX;
1030  // const bool initializeWithZeros = true;
1031  {
1032  // ============== RESTRICTION ==============
1033  RCP<TimeMonitor> RTime;
1034  if (!useStackedTimer)
1035  RTime = rcp(new TimeMonitor(*this, prefix + "Solve : restriction (total)", Timings0));
1036  RCP<TimeMonitor> RLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : restriction" + levelSuffix, Timings0));
1037  coarseRhs = coarseRhs_[startLevel];
1038 
1039  if (implicitTranspose_) {
1040  P->apply(*residual, *coarseRhs, Teuchos::TRANS, one, zero);
1041 
1042  } else {
1043  RCP<Operator> R = Coarse->Get<RCP<Operator>>("R");
1044  R->apply(*residual, *coarseRhs, Teuchos::NO_TRANS, one, zero);
1045  }
1046  }
1047 
1048  RCP<const Import> importer;
1049  if (Coarse->IsAvailable("Importer"))
1050  importer = Coarse->Get<RCP<const Import>>("Importer");
1051 
1052  coarseX = coarseX_[startLevel];
1053  if (!doPRrebalance_ && !importer.is_null()) {
1054  RCP<TimeMonitor> ITime;
1055  if (!useStackedTimer)
1056  ITime = rcp(new TimeMonitor(*this, prefix + "Solve : import (total)", Timings0));
1057  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : import" + levelSuffix1, Timings0));
1058 
1059  // Import: range map of R --> domain map of rebalanced Ac (before subcomm replacement)
1060  RCP<MultiVector> coarseTmp = coarseImport_[startLevel];
1061  coarseTmp->doImport(*coarseRhs, *importer, Xpetra::INSERT);
1062  coarseRhs.swap(coarseTmp);
1063  }
1064 
1065  RCP<Operator> Ac = Coarse->Get<RCP<Operator>>("A");
1066  if (!Ac.is_null()) {
1067  RCP<const Map> origXMap = coarseX->getMap();
1068  RCP<const Map> origRhsMap = coarseRhs->getMap();
1069 
1070  // Replace maps with maps with a subcommunicator
1071  coarseRhs->replaceMap(Ac->getRangeMap());
1072  coarseX->replaceMap(Ac->getDomainMap());
1073 
1074  {
1075  iterateLevelTime = Teuchos::null; // stop timing this level
1076 
1077  Iterate(*coarseRhs, *coarseX, 1, true, startLevel + 1);
1078  // ^^ zero initial guess
1079  if (Cycle_ == WCYCLE && WCycleStartLevel_ >= startLevel)
1080  Iterate(*coarseRhs, *coarseX, 1, false, startLevel + 1);
1081  // ^^ nonzero initial guess
1082 
1083  iterateLevelTime = rcp(new TimeMonitor(*this, iterateLevelTimeLabel)); // restart timing this level
1084  }
1085  coarseX->replaceMap(origXMap);
1086  coarseRhs->replaceMap(origRhsMap);
1087  }
1088 
1089  if (!doPRrebalance_ && !importer.is_null()) {
1090  RCP<TimeMonitor> ITime;
1091  if (!useStackedTimer)
1092  ITime = rcp(new TimeMonitor(*this, prefix + "Solve : export (total)", Timings0));
1093  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : export" + levelSuffix1, Timings0));
1094 
1095  // Import: range map of rebalanced Ac (before subcomm replacement) --> domain map of P
1096  RCP<MultiVector> coarseTmp = coarseExport_[startLevel];
1097  coarseTmp->doExport(*coarseX, *importer, Xpetra::INSERT);
1098  coarseX.swap(coarseTmp);
1099  }
1100 
1101  {
1102  // ============== PROLONGATION ==============
1103  RCP<TimeMonitor> PTime;
1104  if (!useStackedTimer)
1105  PTime = rcp(new TimeMonitor(*this, prefix + "Solve : prolongation (total)", Timings0));
1106  RCP<TimeMonitor> PLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : prolongation" + levelSuffix, Timings0));
1107  // Update X += P * coarseX
1108  // Note that due to what may be round-off error accumulation, use of the fused kernel
1109  // P->apply(*coarseX, X, Teuchos::NO_TRANS, one, one);
1110  // can in some cases result in slightly higher iteration counts.
1111  if (fuseProlongationAndUpdate_) {
1112  P->apply(*coarseX, X, Teuchos::NO_TRANS, scalingFactor_, one);
1113  } else {
1114  RCP<MultiVector> correction = correction_[startLevel];
1115  P->apply(*coarseX, *correction, Teuchos::NO_TRANS, one, zero);
1116  X.update(scalingFactor_, *correction, one);
1117  }
1118  }
1119 
1120  {
1121  // ============== POSTSMOOTHING ==============
1122  RCP<TimeMonitor> STime;
1123  if (!useStackedTimer)
1124  STime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing (total)", Timings0));
1125  RCP<TimeMonitor> SLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing" + levelSuffix, Timings0));
1126 
1127  if (Fine->IsAvailable("PostSmoother")) {
1128  RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
1129  postSmoo->Apply(X, B, false);
1130  }
1131  }
1132  }
1133  zeroGuess = false;
1134 
1135  if (IsCalculationOfResidualRequired(startLevel, conv)) {
1136  ConvergenceStatus convergenceStatus = ComputeResidualAndPrintHistory(*A, X, B, iteration, startLevel, conv, prevNorm);
1137  if (convergenceStatus == MueLu::ConvergenceStatus::Converged)
1138  return convergenceStatus;
1139  }
1140  }
1142 }
1143 #endif
1144 
1145 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1146 void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(const LO& start, const LO& end, const std::string& suffix) {
1147  LO startLevel = (start != -1 ? start : 0);
1148  LO endLevel = (end != -1 ? end : Levels_.size() - 1);
1149 
1151  "MueLu::Hierarchy::Write : startLevel must be <= endLevel");
1152 
1153  TEUCHOS_TEST_FOR_EXCEPTION(startLevel < 0 || endLevel >= Levels_.size(), Exceptions::RuntimeError,
1154  "MueLu::Hierarchy::Write bad start or end level");
1155 
1156  for (LO i = startLevel; i < endLevel + 1; i++) {
1157  RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Levels_[i]->template Get<RCP<Operator>>("A")), P, R;
1158  if (i > 0) {
1159  P = rcp_dynamic_cast<Matrix>(Levels_[i]->template Get<RCP<Operator>>("P"));
1160  if (!implicitTranspose_)
1161  R = rcp_dynamic_cast<Matrix>(Levels_[i]->template Get<RCP<Operator>>("R"));
1162  }
1163 
1164  if (!A.is_null()) Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("A_" + toString(i) + suffix + ".m", *A);
1165  if (!P.is_null()) {
1167  }
1168  if (!R.is_null()) {
1170  }
1171  }
1172 }
1173 
1174 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1175 void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Keep(const std::string& ename, const FactoryBase* factory) {
1176  for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1177  (*it)->Keep(ename, factory);
1178 }
1179 
1180 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1181 void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Delete(const std::string& ename, const FactoryBase* factory) {
1182  for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1183  (*it)->Delete(ename, factory);
1184 }
1185 
1186 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1188  for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1189  (*it)->AddKeepFlag(ename, factory, keep);
1190 }
1191 
1192 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1194  for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1195  (*it)->RemoveKeepFlag(ename, factory, keep);
1196 }
1197 
1198 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1200  if (description_.empty()) {
1201  std::ostringstream out;
1202  out << BaseClass::description();
1203  out << "{#levels = " << GetGlobalNumLevels() << ", complexity = " << GetOperatorComplexity() << "}";
1204  description_ = out.str();
1205  }
1206  return description_;
1207 }
1208 
1209 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1211  describe(out, toMueLuVerbLevel(tVerbLevel));
1212 }
1213 
1214 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1216  RCP<Operator> A0 = Levels_[0]->template Get<RCP<Operator>>("A");
1217  RCP<const Teuchos::Comm<int>> comm = A0->getDomainMap()->getComm();
1218 
1219  int numLevels = GetNumLevels();
1220  RCP<Operator> Ac = Levels_[numLevels - 1]->template Get<RCP<Operator>>("A");
1221  if (Ac.is_null()) {
1222  // It may happen that we do repartition on the last level, but the matrix
1223  // is small enough to satisfy "max coarse size" requirement. Then, even
1224  // though we have the level, the matrix would be null on all but one processors
1225  numLevels--;
1226  }
1227  int root = comm->getRank();
1228 
1229 #ifdef HAVE_MPI
1230  int smartData = numLevels * comm->getSize() + comm->getRank(), maxSmartData;
1231  reduceAll(*comm, Teuchos::REDUCE_MAX, smartData, Teuchos::ptr(&maxSmartData));
1232  root = maxSmartData % comm->getSize();
1233 #endif
1234 
1235  // Compute smoother complexity, if needed
1236  double smoother_comp = -1.0;
1237  if (verbLevel & (Statistics0 | Test))
1238  smoother_comp = GetSmootherComplexity();
1239 
1240  std::string outstr;
1241  if (comm->getRank() == root && verbLevel & (Statistics0 | Test)) {
1242  std::vector<Xpetra::global_size_t> nnzPerLevel;
1243  std::vector<Xpetra::global_size_t> rowsPerLevel;
1244  std::vector<int> numProcsPerLevel;
1245  bool someOpsNotMatrices = false;
1247  for (int i = 0; i < numLevels; i++) {
1248  TEUCHOS_TEST_FOR_EXCEPTION(!(Levels_[i]->IsAvailable("A")), Exceptions::RuntimeError,
1249  "Operator A is not available on level " << i);
1250 
1251  RCP<Operator> A = Levels_[i]->template Get<RCP<Operator>>("A");
1253  "Operator A on level " << i << " is null.");
1254 
1255  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
1256  if (Am.is_null()) {
1257  someOpsNotMatrices = true;
1258  nnzPerLevel.push_back(INVALID);
1259  rowsPerLevel.push_back(A->getDomainMap()->getGlobalNumElements());
1260  numProcsPerLevel.push_back(A->getDomainMap()->getComm()->getSize());
1261  } else {
1262  LO storageblocksize = Am->GetStorageBlockSize();
1263  Xpetra::global_size_t nnz = Am->getGlobalNumEntries() * storageblocksize * storageblocksize;
1264  nnzPerLevel.push_back(nnz);
1265  rowsPerLevel.push_back(Am->getGlobalNumRows() * storageblocksize);
1266  numProcsPerLevel.push_back(Am->getRowMap()->getComm()->getSize());
1267  }
1268  }
1269  if (someOpsNotMatrices)
1270  GetOStream(Warnings0) << "Some level operators are not matrices, statistics calculation are incomplete" << std::endl;
1271 
1272  {
1273  std::string label = Levels_[0]->getObjectLabel();
1274  std::ostringstream oss;
1275  oss << std::setfill(' ');
1276  oss << "\n--------------------------------------------------------------------------------\n";
1277  oss << "--- Multigrid Summary " << std::setw(28) << std::left << label << "---\n";
1278  oss << "--------------------------------------------------------------------------------" << std::endl;
1279  if (verbLevel & Parameters1)
1280  oss << "Scalar = " << Teuchos::ScalarTraits<Scalar>::name() << std::endl;
1281  oss << "Number of levels = " << numLevels << std::endl;
1282  oss << "Operator complexity = " << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1283  if (!someOpsNotMatrices)
1284  oss << GetOperatorComplexity() << std::endl;
1285  else
1286  oss << "not available (Some operators in hierarchy are not matrices.)" << std::endl;
1287 
1288  if (smoother_comp != -1.0) {
1289  oss << "Smoother complexity = " << std::setprecision(2) << std::setiosflags(std::ios::fixed)
1290  << smoother_comp << std::endl;
1291  }
1292 
1293  switch (Cycle_) {
1294  case VCYCLE:
1295  oss << "Cycle type = V" << std::endl;
1296  break;
1297  case WCYCLE:
1298  oss << "Cycle type = W" << std::endl;
1299  if (WCycleStartLevel_ > 0)
1300  oss << "Cycle start level = " << WCycleStartLevel_ << std::endl;
1301  break;
1302  default:
1303  break;
1304  };
1305  oss << std::endl;
1306 
1307  Xpetra::global_size_t tt = rowsPerLevel[0];
1308  int rowspacer = 2;
1309  while (tt != 0) {
1310  tt /= 10;
1311  rowspacer++;
1312  }
1313  for (size_t i = 0; i < nnzPerLevel.size(); ++i) {
1314  tt = nnzPerLevel[i];
1315  if (tt != INVALID)
1316  break;
1317  tt = 100; // This will get used if all levels are operators.
1318  }
1319  int nnzspacer = 2;
1320  while (tt != 0) {
1321  tt /= 10;
1322  nnzspacer++;
1323  }
1324  tt = numProcsPerLevel[0];
1325  int npspacer = 2;
1326  while (tt != 0) {
1327  tt /= 10;
1328  npspacer++;
1329  }
1330  oss << "level " << std::setw(rowspacer) << " rows " << std::setw(nnzspacer) << " nnz "
1331  << " nnz/row" << std::setw(npspacer) << " c ratio"
1332  << " procs" << std::endl;
1333  for (size_t i = 0; i < nnzPerLevel.size(); ++i) {
1334  oss << " " << i << " ";
1335  oss << std::setw(rowspacer) << rowsPerLevel[i];
1336  if (nnzPerLevel[i] != INVALID) {
1337  oss << std::setw(nnzspacer) << nnzPerLevel[i];
1338  oss << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1339  oss << std::setw(9) << as<double>(nnzPerLevel[i]) / rowsPerLevel[i];
1340  } else {
1341  oss << std::setw(nnzspacer) << "Operator";
1342  oss << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1343  oss << std::setw(9) << " ";
1344  }
1345  if (i)
1346  oss << std::setw(9) << as<double>(rowsPerLevel[i - 1]) / rowsPerLevel[i];
1347  else
1348  oss << std::setw(9) << " ";
1349  oss << " " << std::setw(npspacer) << numProcsPerLevel[i] << std::endl;
1350  }
1351  oss << std::endl;
1352  for (int i = 0; i < GetNumLevels(); ++i) {
1353  RCP<SmootherBase> preSmoo, postSmoo;
1354  if (Levels_[i]->IsAvailable("PreSmoother"))
1355  preSmoo = Levels_[i]->template Get<RCP<SmootherBase>>("PreSmoother");
1356  if (Levels_[i]->IsAvailable("PostSmoother"))
1357  postSmoo = Levels_[i]->template Get<RCP<SmootherBase>>("PostSmoother");
1358 
1359  if (preSmoo != null && preSmoo == postSmoo)
1360  oss << "Smoother (level " << i << ") both : " << preSmoo->description() << std::endl;
1361  else {
1362  oss << "Smoother (level " << i << ") pre : "
1363  << (preSmoo != null ? preSmoo->description() : "no smoother") << std::endl;
1364  oss << "Smoother (level " << i << ") post : "
1365  << (postSmoo != null ? postSmoo->description() : "no smoother") << std::endl;
1366  }
1367 
1368  oss << std::endl;
1369  }
1370 
1371  outstr = oss.str();
1372  }
1373  }
1374 
1375 #ifdef HAVE_MPI
1376  RCP<const Teuchos::MpiComm<int>> mpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
1377  MPI_Comm rawComm = (*mpiComm->getRawMpiComm())();
1378 
1379  int strLength = outstr.size();
1380  MPI_Bcast(&strLength, 1, MPI_INT, root, rawComm);
1381  if (comm->getRank() != root)
1382  outstr.resize(strLength);
1383  MPI_Bcast(&outstr[0], strLength, MPI_CHAR, root, rawComm);
1384 #endif
1385 
1386  out << outstr;
1387 }
1388 
1389 // NOTE: at some point this should be replaced by a friend operator <<
1390 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1391 void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(std::ostream& out, const VerbLevel verbLevel) const {
1392  Teuchos::OSTab tab2(out);
1393  for (int i = 0; i < GetNumLevels(); ++i)
1394  Levels_[i]->print(out, verbLevel);
1395 }
1396 
1397 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1399  isPreconditioner_ = flag;
1400 }
1401 
1402 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1404  if (GetProcRankVerbose() != 0)
1405  return;
1406 #if defined(HAVE_MUELU_BOOST) && defined(HAVE_MUELU_BOOST_FOR_REAL) && defined(BOOST_VERSION) && (BOOST_VERSION >= 104400)
1407 
1408  BoostGraph graph;
1409 
1410  BoostProperties dp;
1411  dp.property("label", boost::get(boost::vertex_name, graph));
1412  dp.property("id", boost::get(boost::vertex_index, graph));
1413  dp.property("label", boost::get(boost::edge_name, graph));
1414  dp.property("color", boost::get(boost::edge_color, graph));
1415 
1416  // create local maps
1417  std::map<const FactoryBase*, BoostVertex> vindices;
1418  typedef std::map<std::pair<BoostVertex, BoostVertex>, std::string> emap;
1419  emap edges;
1420 
1421  static int call_id = 0;
1422 
1423  RCP<Operator> A = Levels_[0]->template Get<RCP<Operator>>("A");
1424  int rank = A->getDomainMap()->getComm()->getRank();
1425 
1426  // printf("[%d] CMS: ----------------------\n",rank);
1427  for (int i = currLevel; i <= currLevel + 1 && i < GetNumLevels(); i++) {
1428  edges.clear();
1429  Levels_[i]->UpdateGraph(vindices, edges, dp, graph);
1430 
1431  for (emap::const_iterator eit = edges.begin(); eit != edges.end(); eit++) {
1432  std::pair<BoostEdge, bool> boost_edge = boost::add_edge(eit->first.first, eit->first.second, graph);
1433  // printf("[%d] CMS: Hierarchy, adding edge (%d->%d) %d\n",rank,(int)eit->first.first,(int)eit->first.second,(int)boost_edge.second);
1434  // Because xdot.py views 'Graph' as a keyword
1435  if (eit->second == std::string("Graph"))
1436  boost::put("label", dp, boost_edge.first, std::string("Graph_"));
1437  else
1438  boost::put("label", dp, boost_edge.first, eit->second);
1439  if (i == currLevel)
1440  boost::put("color", dp, boost_edge.first, std::string("red"));
1441  else
1442  boost::put("color", dp, boost_edge.first, std::string("blue"));
1443  }
1444  }
1445 
1446  std::ofstream out(dumpFile_.c_str() + std::string("_") + std::to_string(currLevel) + std::string("_") + std::to_string(call_id) + std::string("_") + std::to_string(rank) + std::string(".dot"));
1447  boost::write_graphviz_dp(out, graph, dp, std::string("id"));
1448  out.close();
1449  call_id++;
1450 #else
1451  GetOStream(Errors) << "Dependency graph output requires boost and MueLu_ENABLE_Boost_for_real" << std::endl;
1452 #endif
1453 }
1454 
1455 // Enforce that coordinate vector's map is consistent with that of A
1456 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1458  RCP<Operator> Ao = level.Get<RCP<Operator>>("A");
1459  RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Ao);
1460  if (A.is_null()) {
1461  GetOStream(Runtime1) << "Hierarchy::ReplaceCoordinateMap: operator is not a matrix, skipping..." << std::endl;
1462  return;
1463  }
1464  if (Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A) != Teuchos::null) {
1465  GetOStream(Runtime1) << "Hierarchy::ReplaceCoordinateMap: operator is a BlockedCrsMatrix, skipping..." << std::endl;
1466  return;
1467  }
1468 
1470 
1471  RCP<xdMV> coords = level.Get<RCP<xdMV>>("Coordinates");
1472 
1473  if (A->getRowMap()->isSameAs(*(coords->getMap()))) {
1474  GetOStream(Runtime1) << "Hierarchy::ReplaceCoordinateMap: matrix and coordinates maps are same, skipping..." << std::endl;
1475  return;
1476  }
1477 
1478  if (A->IsView("stridedMaps") && rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps")) != Teuchos::null) {
1479  RCP<const StridedMap> stridedRowMap = rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps"));
1480 
1481  // It is better to through an exceptions if maps may be inconsistent, than to ignore it and experience unfathomable breakdowns
1482  TEUCHOS_TEST_FOR_EXCEPTION(stridedRowMap->getStridedBlockId() != -1 || stridedRowMap->getOffset() != 0,
1483  Exceptions::RuntimeError, "Hierarchy::ReplaceCoordinateMap: nontrivial maps (block id = " << stridedRowMap->getStridedBlockId() << ", offset = " << stridedRowMap->getOffset() << ")");
1484  }
1485 
1486  GetOStream(Runtime1) << "Replacing coordinate map" << std::endl;
1487  TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0, Exceptions::RuntimeError, "Hierarchy::ReplaceCoordinateMap: Storage block size does not evenly divide fixed block size");
1488 
1489  size_t blkSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
1490 
1491  RCP<const Map> nodeMap = A->getRowMap();
1492  if (blkSize > 1) {
1493  // Create a nodal map, as coordinates have not been expanded to a DOF map yet.
1494  RCP<const Map> dofMap = A->getRowMap();
1495  GO indexBase = dofMap->getIndexBase();
1496  size_t numLocalDOFs = dofMap->getLocalNumElements();
1497  TEUCHOS_TEST_FOR_EXCEPTION(numLocalDOFs % blkSize, Exceptions::RuntimeError,
1498  "Hierarchy::ReplaceCoordinateMap: block size (" << blkSize << ") is incompatible with the number of local dofs in a row map (" << numLocalDOFs);
1499  ArrayView<const GO> GIDs = dofMap->getLocalElementList();
1500 
1501  Array<GO> nodeGIDs(numLocalDOFs / blkSize);
1502  for (size_t i = 0; i < numLocalDOFs; i += blkSize)
1503  nodeGIDs[i / blkSize] = (GIDs[i] - indexBase) / blkSize + indexBase;
1504 
1506  nodeMap = MapFactory::Build(dofMap->lib(), INVALID, nodeGIDs(), indexBase, dofMap->getComm());
1507  } else {
1508  // blkSize == 1
1509  // Check whether the length of vectors fits to the size of A
1510  // If yes, make sure that the maps are matching
1511  // If no, throw a warning but do not touch the Coordinates
1512  if (coords->getLocalLength() != A->getRowMap()->getLocalNumElements()) {
1513  GetOStream(Warnings) << "Coordinate vector does not match row map of matrix A!" << std::endl;
1514  return;
1515  }
1516  }
1517 
1519  std::vector<ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>> coordData;
1520  for (size_t i = 0; i < coords->getNumVectors(); i++) {
1521  coordData.push_back(coords->getData(i));
1522  coordDataView.push_back(coordData[i]());
1523  }
1524 
1525  RCP<xdMV> newCoords = Xpetra::MultiVectorFactory<typename Teuchos::ScalarTraits<Scalar>::coordinateType, LO, GO, NO>::Build(nodeMap, coordDataView(), coords->getNumVectors());
1526  level.Set("Coordinates", newCoords);
1527 }
1528 
1529 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1531  int N = Levels_.size();
1532  if (((sizeOfAllocatedLevelMultiVectors_ == numvecs && residual_.size() == N) || numvecs <= 0) && !forceMapCheck) return;
1533 
1534  // If, somehow, we changed the number of levels, delete everything first
1535  if (residual_.size() != N) {
1536  DeleteLevelMultiVectors();
1537 
1538  residual_.resize(N);
1539  coarseRhs_.resize(N);
1540  coarseX_.resize(N);
1541  coarseImport_.resize(N);
1542  coarseExport_.resize(N);
1543  correction_.resize(N);
1544  }
1545 
1546  for (int i = 0; i < N; i++) {
1547  RCP<Operator> A = Levels_[i]->template Get<RCP<Operator>>("A");
1548  if (!A.is_null()) {
1549  // This dance is because we allow A to have a BlockedMap and X/B to have (compatible) non-blocked map
1550  RCP<const BlockedCrsMatrix> A_as_blocked = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(A);
1551  RCP<const Map> Arm = A->getRangeMap();
1552  RCP<const Map> Adm = A->getDomainMap();
1553  if (!A_as_blocked.is_null()) {
1554  Adm = A_as_blocked->getFullDomainMap();
1555  }
1556 
1557  if (residual_[i].is_null() || !residual_[i]->getMap()->isSameAs(*Arm))
1558  // This is zero'd by default since it is filled via an operator apply
1559  residual_[i] = MultiVectorFactory::Build(Arm, numvecs, true);
1560  if (correction_[i].is_null() || !correction_[i]->getMap()->isSameAs(*Adm))
1561  correction_[i] = MultiVectorFactory::Build(Adm, numvecs, false);
1562  }
1563 
1564  if (i + 1 < N) {
1565  // This is zero'd by default since it is filled via an operator apply
1566  if (implicitTranspose_) {
1567  RCP<Operator> P = Levels_[i + 1]->template Get<RCP<Operator>>("P");
1568  if (!P.is_null()) {
1569  RCP<const Map> map = P->getDomainMap();
1570  if (coarseRhs_[i].is_null() || !coarseRhs_[i]->getMap()->isSameAs(*map))
1571  coarseRhs_[i] = MultiVectorFactory::Build(map, numvecs, true);
1572  }
1573  } else {
1574  RCP<Operator> R = Levels_[i + 1]->template Get<RCP<Operator>>("R");
1575  if (!R.is_null()) {
1576  RCP<const Map> map = R->getRangeMap();
1577  if (coarseRhs_[i].is_null() || !coarseRhs_[i]->getMap()->isSameAs(*map))
1578  coarseRhs_[i] = MultiVectorFactory::Build(map, numvecs, true);
1579  }
1580  }
1581 
1582  RCP<const Import> importer;
1583  if (Levels_[i + 1]->IsAvailable("Importer"))
1584  importer = Levels_[i + 1]->template Get<RCP<const Import>>("Importer");
1585  if (doPRrebalance_ || importer.is_null()) {
1586  RCP<const Map> map = coarseRhs_[i]->getMap();
1587  if (coarseX_[i].is_null() || !coarseX_[i]->getMap()->isSameAs(*map))
1588  coarseX_[i] = MultiVectorFactory::Build(map, numvecs, true);
1589  } else {
1591  map = importer->getTargetMap();
1592  if (coarseImport_[i].is_null() || !coarseImport_[i]->getMap()->isSameAs(*map)) {
1593  coarseImport_[i] = MultiVectorFactory::Build(map, numvecs, false);
1594  coarseX_[i] = MultiVectorFactory::Build(map, numvecs, false);
1595  }
1596  map = importer->getSourceMap();
1597  if (coarseExport_[i].is_null() || !coarseExport_[i]->getMap()->isSameAs(*map))
1598  coarseExport_[i] = MultiVectorFactory::Build(map, numvecs, false);
1599  }
1600  }
1601  }
1602  sizeOfAllocatedLevelMultiVectors_ = numvecs;
1603 }
1604 
1605 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1607  if (sizeOfAllocatedLevelMultiVectors_ == 0) return;
1608  residual_.resize(0);
1609  coarseRhs_.resize(0);
1610  coarseX_.resize(0);
1611  coarseImport_.resize(0);
1612  coarseExport_.resize(0);
1613  correction_.resize(0);
1614  sizeOfAllocatedLevelMultiVectors_ = 0;
1615 }
1616 
1617 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1619  const LO startLevel, const ConvData& conv) const {
1620  return (startLevel == 0 && !isPreconditioner_ && (IsPrint(Statistics1) || conv.tol_ > 0));
1621 }
1622 
1623 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1625  const Teuchos::Array<MagnitudeType>& residualNorm, const MagnitudeType convergenceTolerance) const {
1626  ConvergenceStatus convergenceStatus = ConvergenceStatus::Undefined;
1627 
1628  if (convergenceTolerance > Teuchos::ScalarTraits<MagnitudeType>::zero()) {
1629  bool passed = true;
1630  for (LO k = 0; k < residualNorm.size(); k++)
1631  if (residualNorm[k] >= convergenceTolerance)
1632  passed = false;
1633 
1634  if (passed)
1635  convergenceStatus = ConvergenceStatus::Converged;
1636  else
1637  convergenceStatus = ConvergenceStatus::Unconverged;
1638  }
1639 
1640  return convergenceStatus;
1641 }
1642 
1643 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1645  const LO iteration, const Teuchos::Array<MagnitudeType>& residualNorm) const {
1646  GetOStream(Statistics1) << "iter: "
1647  << std::setiosflags(std::ios::left)
1648  << std::setprecision(3) << std::setw(4) << iteration
1649  << " residual = "
1650  << std::setprecision(10) << residualNorm
1651  << std::endl;
1652 }
1653 
1654 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1656  const Operator& A, const MultiVector& X, const MultiVector& B, const LO iteration,
1657  const LO startLevel, const ConvData& conv, MagnitudeType& previousResidualNorm) {
1658  Teuchos::Array<MagnitudeType> residualNorm;
1659  residualNorm = Utilities::ResidualNorm(A, X, B, *residual_[startLevel]);
1660 
1661  const MagnitudeType currentResidualNorm = residualNorm[0];
1662  rate_ = currentResidualNorm / previousResidualNorm;
1663  previousResidualNorm = currentResidualNorm;
1664 
1665  if (IsPrint(Statistics1))
1666  PrintResidualHistory(iteration, residualNorm);
1667 
1668  return IsConverged(residualNorm, conv.tol_);
1669 }
1670 
1671 } // namespace MueLu
1672 
1673 #endif // MUELU_HIERARCHY_DEF_HPP
Important warning messages (one line)
void Build(Level &level) const
Build an object with this factory.
void IsPreconditioner(const bool flag)
High level timing information (use Teuchos::TimeMonitor::summarize() to print)
virtual std::string getObjectLabel() const
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.
bool is_null(const boost::shared_ptr< T > &p)
RCP< Level > & GetLevel(const int levelID=0)
Retrieve a certain level from hierarchy.
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
Hierarchy()
Default constructor.
virtual size_t getNodeSmootherComplexity() const =0
Compute a rough estimate of the cost to apply this smoother on this MPI rank. Return Teuchos::Ordinal...
void Release(const FactoryBase &factory)
Decrement the storage counter for all the inputs of a factory.
GlobalOrdinal GO
static RCP< Time > getNewCounter(const std::string &name)
void AddLevel(const RCP< Level > &level)
Add a level at the end of the hierarchy.
void CheckForEmptySmoothersAndCoarseSolve()
void PrintResidualHistory(const LO iteration, const Teuchos::Array< MagnitudeType > &residualNorm) const
Print residualNorm for this iteration to the screen.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
short KeepType
static void Write(const std::string &fileName, const Xpetra::Map< LocalOrdinal, GlobalOrdinal, Node > &M)
void DumpCurrentGraph(int level) const
Print more statistics.
void AddNewLevel()
Add a new level at the end of the hierarchy.
VerbLevel toMueLuVerbLevel(const Teuchos::EVerbosityLevel verbLevel)
Translate Teuchos verbosity level to MueLu verbosity level.
void swap(RCP< T > &r_ptr)
LocalOrdinal LO
One-liner description of what is happening.
void Clear(int startLevel=0)
Clear impermanent data from previous setup.
void SetPreviousLevel(const RCP< Level > &previousLevel)
Definition: MueLu_Level.cpp:62
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Exception throws to report incompatible objects (like maps).
static void SetRandomSeed(const Teuchos::Comm< int > &comm)
Set seed for random number generator.
Integrates Teuchos::TimeMonitor with MueLu verbosity system.
static std::string name()
static const NoFactory * get()
ConvergenceStatus Iterate(const MultiVector &B, MultiVector &X, ConvData conv=ConvData(), bool InitialGuessIsZero=false, LO startLevel=0)
Apply the multigrid preconditioner.
void ReplaceCoordinateMap(Level &level)
static std::string getColonLabel(const std::string &label)
Helper function for object label.
void AddKeepFlag(const std::string &ename, const FactoryBase *factory=NoFactory::get(), KeepType keep=MueLu::Keep)
Call Level::AddKeepFlag for each level of the Hierarchy.
Print even more statistics.
void setlib(Xpetra::UnderlyingLib lib2)
Additional warnings.
void print(std::ostream &out=std::cout, const VerbLevel verbLevel=(MueLu::Parameters|MueLu::Statistics0)) const
Hierarchy::print is local hierarchy function, thus the statistics can be different from global ones...
double GetSmootherComplexity() const
Base class for factories (e.g., R, P, and A_coarse).
Print statistics that do not involve significant additional computation.
Xpetra::UnderlyingLib lib_
Epetra/Tpetra mode.
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void Write(const LO &start=-1, const LO &end=-1, const std::string &suffix="")
Print matrices in the multigrid hierarchy to file.
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
std::string description() const
Return a simple one-line description of this object.
Class that provides default factories within Needs class.
void RemoveKeepFlag(const std::string &ename, const FactoryBase *factory, KeepType keep=MueLu::All)
Call Level::RemoveKeepFlag for each level of the Hierarchy.
void CheckLevel(Level &level, int levelID)
Helper function.
Xpetra::UnderlyingLib lib()
virtual void setObjectLabel(const std::string &objectLabel)
void AllocateLevelMultiVectors(int numvecs, bool forceMapCheck=false)
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
size_t global_size_t
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
void SetMatvecParams(RCP< ParameterList > matvecParams)
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
int GetGlobalNumLevels() const
void push_back(const value_type &x)
RCP< Level > & GetPreviousLevel()
Previous level.
Definition: MueLu_Level.cpp:60
static Teuchos::Array< Magnitude > ResidualNorm(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
Data struct for defining stopping criteria of multigrid iteration.
void SetLevelID(int levelID)
Set level number.
Definition: MueLu_Level.cpp:53
STS::magnitudeType MagnitudeType
void Delete(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Call Level::Delete(ename, factory) for each level of the Hierarchy.
Timer to be used in non-factories.
size_type size() const
Array< RCP< Level > > Levels_
Container for Level objects.
Scalar SC
bool IsCalculationOfResidualRequired(const LO startLevel, const ConvData &conv) const
Decide if the residual needs to be computed.
Node NO
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:51
Print class parameters (more parameters, more verbose)
virtual ~Hierarchy()
Destructor.
void residual(const Operator< SC, LO, GO, NO > &Aop, const MultiVector< SC, LO, GO, NO > &X_in, const MultiVector< SC, LO, GO, NO > &B_in, MultiVector< SC, LO, GO, NO > &R_in)
Exception throws to report errors in the internal logical of the program.
An exception safe way to call the method &#39;Level::SetFactoryManager()&#39;.
void SetComm(RCP< const Teuchos::Comm< int > > const &comm)
void describe(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the Hierarchy with some verbosity level to a FancyOStream object.
Print all warning messages.
Description of what is happening (more verbose)
void Keep(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Call Level::Keep(ename, factory) for each level of the Hierarchy.
ConvergenceStatus IsConverged(const Teuchos::Array< MagnitudeType > &residualNorm, const MagnitudeType convergenceTolerance) const
Decide if the multigrid iteration is converged.
double GetOperatorComplexity() const
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.
RCP< const Teuchos::Comm< int > > GetComm() const
ConvergenceStatus ComputeResidualAndPrintHistory(const Operator &A, const MultiVector &X, const MultiVector &B, const LO iteration, const LO startLevel, const ConvData &conv, MagnitudeType &previousResidualNorm)
Compute the residual norm and print it depending on the verbosity level.
virtual std::string description() const
Return a simple one-line description of this object.
Provides methods to build a multigrid hierarchy and apply multigrid cycles.
std::string toString(const T &t)
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need&#39;s value has been saved.
void Request(const FactoryBase &factory)
Increment the storage counter for all the inputs of a factory.
bool is_null() const