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