MueLu  Version of the Day
MueLu_Hierarchy_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 
47 #ifndef MUELU_HIERARCHY_DEF_HPP
48 #define MUELU_HIERARCHY_DEF_HPP
49 
50 #include <time.h>
51 
52 #include <algorithm>
53 #include <sstream>
54 
55 #include <Xpetra_Matrix.hpp>
56 #include <Xpetra_MultiVectorFactory.hpp>
57 #include <Xpetra_Operator.hpp>
58 #include <Xpetra_IO.hpp>
59 
60 #include "MueLu_Hierarchy_decl.hpp"
61 
62 #include "MueLu_BoostGraphviz.hpp"
63 #include "MueLu_FactoryManager.hpp"
64 #include "MueLu_HierarchyUtils.hpp"
65 #include "MueLu_TopRAPFactory.hpp"
66 #include "MueLu_TopSmootherFactory.hpp"
67 #include "MueLu_Level.hpp"
68 #include "MueLu_Monitor.hpp"
69 #include "MueLu_PerfUtils.hpp"
70 #include "MueLu_PFactory.hpp"
72 #include "MueLu_SmootherFactory.hpp"
73 #include "MueLu_SmootherBase.hpp"
74 
75 #include "Teuchos_TimeMonitor.hpp"
76 
77 namespace MueLu {
78 
79  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
81  : maxCoarseSize_(GetDefaultMaxCoarseSize()), implicitTranspose_(GetDefaultImplicitTranspose()),
82  doPRrebalance_(GetDefaultPRrebalance()), isPreconditioner_(true), Cycle_(GetDefaultCycle()),
83  scalingFactor_(Teuchos::ScalarTraits<double>::one()), lib_(Xpetra::UseTpetra), isDumpingEnabled_(false), dumpLevel_(-1), rate_(-1)
84  {
85  AddLevel(rcp(new Level));
86  }
87 
88  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
92  scalingFactor_(Teuchos::ScalarTraits<double>::one()), isDumpingEnabled_(false), dumpLevel_(-1), rate_(-1)
93  {
94  lib_ = A->getDomainMap()->lib();
95 
96  RCP<Level> Finest = rcp(new Level);
97  AddLevel(Finest);
98 
99  Finest->Set("A", A);
100  }
101 
102  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
104  int levelID = LastLevelID() + 1; // ID of the inserted level
105 
106  if (level->GetLevelID() != -1 && (level->GetLevelID() != levelID))
107  GetOStream(Warnings1) << "Hierarchy::AddLevel(): Level with ID=" << level->GetLevelID() <<
108  " have been added at the end of the hierarchy\n but its ID have been redefined" <<
109  " because last level ID of the hierarchy was " << LastLevelID() << "." << std::endl;
110 
111  Levels_.push_back(level);
112  level->SetLevelID(levelID);
113  level->setlib(lib_);
114 
115  level->SetPreviousLevel( (levelID == 0) ? Teuchos::null : Levels_[LastLevelID() - 1] );
116  }
117 
118  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
120  RCP<Level> newLevel = Levels_[LastLevelID()]->Build(); // new coarse level, using copy constructor
121  newLevel->setlib(lib_);
122  this->AddLevel(newLevel); // add to hierarchy
123  }
124 
125  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
127  TEUCHOS_TEST_FOR_EXCEPTION(levelID < 0 || levelID > LastLevelID(), Exceptions::RuntimeError,
128  "MueLu::Hierarchy::GetLevel(): invalid input parameter value: LevelID = " << levelID);
129  return Levels_[levelID];
130  }
131 
132  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
134  return Levels_.size();
135  }
136 
137  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
139  RCP<Operator> A = Levels_[0]->template Get<RCP<Operator> >("A");
140  RCP<const Teuchos::Comm<int> > comm = A->getDomainMap()->getComm();
141 
142  int numLevels = GetNumLevels();
143  int numGlobalLevels;
144  Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, numLevels, Teuchos::ptr(&numGlobalLevels));
145 
146  return numGlobalLevels;
147  }
148 
149  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
151  double totalNnz = 0, lev0Nnz = 1;
152  for (int i = 0; i < GetNumLevels(); ++i) {
153  TEUCHOS_TEST_FOR_EXCEPTION(!(Levels_[i]->IsAvailable("A")) , Exceptions::RuntimeError,
154  "Operator complexity cannot be calculated because A is unavailable on level " << i);
155  RCP<Operator> A = Levels_[i]->template Get<RCP<Operator> >("A");
156  if (A.is_null())
157  break;
158 
159  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
160  if (Am.is_null()) {
161  GetOStream(Warnings0) << "Some level operators are not matrices, operator complexity calculation aborted" << std::endl;
162  return 0.0;
163  }
164 
165  totalNnz += as<double>(Am->getGlobalNumEntries());
166  if (i == 0)
167  lev0Nnz = totalNnz;
168  }
169  return totalNnz / lev0Nnz;
170  }
171 
172  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
174  double node_sc = 0, global_sc=0;
175  double a0_nnz =0;
176  const size_t INVALID = Teuchos::OrdinalTraits<size_t>::invalid();
177  // Get cost of fine matvec
178  if (GetNumLevels() <= 0) return -1.0;
179  if (!Levels_[0]->IsAvailable("A")) return -1.0;
180 
181  RCP<Operator> A = Levels_[0]->template Get<RCP<Operator> >("A");
182  if (A.is_null()) return -1.0;
183  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
184  if(Am.is_null()) return -1.0;
185  a0_nnz = as<double>(Am->getGlobalNumEntries());
186 
187  // Get smoother complexity at each level
188  for (int i = 0; i < GetNumLevels(); ++i) {
189  size_t level_sc=0;
190  if(!Levels_[i]->IsAvailable("PreSmoother")) continue;
191  RCP<SmootherBase> S = Levels_[i]->template Get<RCP<SmootherBase> >("PreSmoother");
192  if (S.is_null()) continue;
193  level_sc = S->getNodeSmootherComplexity();
194  if(level_sc == INVALID) {global_sc=-1.0;break;}
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) return -1.0;
205  else return global_sc / a0_nnz;
206  }
207 
208 
209 
210 
211  // Coherence checks todo in Setup() (using an helper function):
212  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
214  TEUCHOS_TEST_FOR_EXCEPTION(level.lib() != lib_, Exceptions::RuntimeError,
215  "MueLu::Hierarchy::CheckLevel(): wrong underlying linear algebra library.");
216  TEUCHOS_TEST_FOR_EXCEPTION(level.GetLevelID() != levelID, Exceptions::RuntimeError,
217  "MueLu::Hierarchy::CheckLevel(): wrong level ID");
218  TEUCHOS_TEST_FOR_EXCEPTION(levelID != 0 && level.GetPreviousLevel() != Levels_[levelID-1], Exceptions::RuntimeError,
219  "MueLu::Hierarchy::Setup(): wrong level parent");
220  }
221 
222  // The function uses three managers: fine, coarse and next coarse
223  // We construct the data for the coarse level, and do requests for the next coarse
224  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
226  const RCP<const FactoryManagerBase> fineLevelManager,
227  const RCP<const FactoryManagerBase> coarseLevelManager,
228  const RCP<const FactoryManagerBase> nextLevelManager) {
229  // Use PrintMonitor/TimerMonitor instead of just a FactoryMonitor to print "Level 0" instead of Hierarchy(0)
230  // Print is done after the requests for next coarse level
231  TimeMonitor m1(*this, this->ShortClassName() + ": " + "Setup (total)");
232  TimeMonitor m2(*this, this->ShortClassName() + ": " + "Setup" + " (total, level=" + Teuchos::toString(coarseLevelID) + ")");
233 
234  // TODO: pass coarseLevelManager by reference
235  TEUCHOS_TEST_FOR_EXCEPTION(coarseLevelManager == Teuchos::null, Exceptions::RuntimeError,
236  "MueLu::Hierarchy::Setup(): argument coarseLevelManager cannot be null");
237 
240 
241  TEUCHOS_TEST_FOR_EXCEPTION(LastLevelID() < coarseLevelID, Exceptions::RuntimeError,
242  "MueLu::Hierarchy:Setup(): level " << coarseLevelID << " (specified by coarseLevelID argument) "
243  "must be built before calling this function.");
244 
245  Level& level = *Levels_[coarseLevelID];
246 
247  if (levelManagers_.size() < coarseLevelID+1)
248  levelManagers_.resize(coarseLevelID+1);
249  levelManagers_[coarseLevelID] = coarseLevelManager;
250 
251  bool isFinestLevel = (fineLevelManager.is_null());
252  bool isLastLevel = (nextLevelManager.is_null());
253 
254  int oldRank = -1;
255  if (isFinestLevel) {
256  RCP<Operator> A = level.Get< RCP<Operator> >("A");
257  RCP<const Map> domainMap = A->getDomainMap();
258  RCP<const Teuchos::Comm<int> > comm = domainMap->getComm();
259 
260  // Initialize random seed for reproducibility
262 
263  // Record the communicator on the level (used for timers sync)
264  level.SetComm(comm);
265  oldRank = SetProcRankVerbose(comm->getRank());
266 
267  // Set the Hierarchy library to match that of the finest level matrix,
268  // even if it was already set
269  lib_ = domainMap->lib();
270  level.setlib(lib_);
271 
272  } else {
273  // Permeate library to a coarser level
274  level.setlib(lib_);
275 
276  Level& prevLevel = *Levels_[coarseLevelID-1];
277  oldRank = SetProcRankVerbose(prevLevel.GetComm()->getRank());
278  }
279 
280  CheckLevel(level, coarseLevelID);
281 
282  // Attach FactoryManager to the fine level
283  RCP<SetFactoryManager> SFMFine;
284  if (!isFinestLevel)
285  SFMFine = rcp(new SetFactoryManager(Levels_[coarseLevelID-1], fineLevelManager));
286 
287  if (isFinestLevel && Levels_[coarseLevelID]->IsAvailable("Coordinates"))
288  ReplaceCoordinateMap(*Levels_[coarseLevelID]);
289 
290  // Attach FactoryManager to the coarse level
291  SetFactoryManager SFMCoarse(Levels_[coarseLevelID], coarseLevelManager);
292 
293  if (isDumpingEnabled_ && dumpLevel_ == 0 && coarseLevelID == 1)
295 
296  RCP<TopSmootherFactory> coarseFact = rcp(new TopSmootherFactory(coarseLevelManager, "CoarseSolver"));
297  RCP<TopSmootherFactory> smootherFact = rcp(new TopSmootherFactory(coarseLevelManager, "Smoother"));
298 
299  int nextLevelID = coarseLevelID + 1;
300 
301  RCP<SetFactoryManager> SFMNext;
302  if (isLastLevel == false) {
303  // We are not at the coarsest level, so there is going to be another level ("next coarse") after this one ("coarse")
304  if (nextLevelID > LastLevelID())
305  AddNewLevel();
306  CheckLevel(*Levels_[nextLevelID], nextLevelID);
307 
308  // Attach FactoryManager to the next level (level after coarse)
309  SFMNext = rcp(new SetFactoryManager(Levels_[nextLevelID], nextLevelManager));
310  Levels_[nextLevelID]->Request(TopRAPFactory(coarseLevelManager, nextLevelManager));
311 
312  // Do smoother requests here. We don't know whether this is going to be
313  // the coarsest level or not, but we need to DeclareInput before we call
314  // coarseRAPFactory.Build(), otherwise some stuff may be erased after
315  // level releases
316  level.Request(*smootherFact);
317 
318  } else {
319  // Similar to smoother above, do the coarse solver request here. We don't
320  // know whether this is going to be the coarsest level or not, but we
321  // need to DeclareInput before we call coarseRAPFactory.Build(),
322  // otherwise some stuff may be erased after level releases. This is
323  // actually evident on ProjectorSmoother. It requires both "A" and
324  // "Nullspace". However, "Nullspace" is erased after all releases, so if
325  // we call the coarse factory request after RAP build we would not have
326  // any data, and cannot get it as we don't have previous managers. The
327  // typical trace looks like this:
328  //
329  // MueLu::Level(0)::GetFactory(Aggregates, 0): No FactoryManager
330  // during request for data " Aggregates" on level 0 by factory TentativePFactory
331  // during request for data " P" on level 1 by factory EminPFactory
332  // during request for data " P" on level 1 by factory TransPFactory
333  // during request for data " R" on level 1 by factory RAPFactory
334  // during request for data " A" on level 1 by factory TentativePFactory
335  // during request for data " Nullspace" on level 2 by factory NullspaceFactory
336  // during request for data " Nullspace" on level 2 by factory NullspacePresmoothFactory
337  // during request for data " Nullspace" on level 2 by factory ProjectorSmoother
338  // during request for data " PreSmoother" on level 2 by factory NoFactory
339  level.Request(*coarseFact);
340  }
341 
342  PrintMonitor m0(*this, "Level " + Teuchos::toString(coarseLevelID), static_cast<MsgType>(Runtime0 | Test));
343 
344  // Build coarse level hierarchy
345  RCP<Operator> Ac = Teuchos::null;
346  TopRAPFactory coarseRAPFactory(fineLevelManager, coarseLevelManager);
347 
348  if (level.IsAvailable("A")) {
349  Ac = level.Get<RCP<Operator> >("A");
350  } else if (!isFinestLevel) {
351  // We only build here, the release is done later
352  coarseRAPFactory.Build(*level.GetPreviousLevel(), level);
353  }
354 
355  if (level.IsAvailable("A"))
356  Ac = level.Get<RCP<Operator> >("A");
357  RCP<Matrix> Acm = rcp_dynamic_cast<Matrix>(Ac);
358 
359  // Record the communicator on the level
360  if (!Ac.is_null())
361  level.SetComm(Ac->getDomainMap()->getComm());
362 
363  // Test if we reach the end of the hierarchy
364  bool isOrigLastLevel = isLastLevel;
365  if (isLastLevel) {
366  // Last level as we have achieved the max limit
367  isLastLevel = true;
368 
369  } else if (Ac.is_null()) {
370  // Last level for this processor, as it does not belong to the next
371  // subcommunicator. Other processors may continue working on the
372  // hierarchy
373  isLastLevel = true;
374 
375  } else {
376  if (!Acm.is_null() && Acm->getGlobalNumRows() <= maxCoarseSize_) {
377  // Last level as the size of the coarse matrix became too small
378  GetOStream(Runtime0) << "Max coarse size (<= " << maxCoarseSize_ << ") achieved" << std::endl;
379  isLastLevel = true;
380  }
381  }
382 
383  if (!Ac.is_null() && !isFinestLevel) {
384  RCP<Operator> A = Levels_[coarseLevelID-1]->template Get< RCP<Operator> >("A");
385  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
386 
387  const double maxCoarse2FineRatio = 0.8;
388  if (!Acm.is_null() && !Am.is_null() && Acm->getGlobalNumRows() > maxCoarse2FineRatio * Am->getGlobalNumRows()) {
389  // We could abort here, but for now we simply notify user.
390  // Couple of additional points:
391  // - if repartitioning is delayed until level K, but the aggregation
392  // procedure stagnates between levels K-1 and K. In this case,
393  // repartitioning could enable faster coarsening once again, but the
394  // hierarchy construction will abort due to the stagnation check.
395  // - if the matrix is small enough, we could move it to one processor.
396  GetOStream(Warnings0) << "Aggregation stagnated. Please check your matrix and/or adjust your configuration file."
397  << "Possible fixes:\n"
398  << " - reduce the maximum number of levels\n"
399  << " - enable repartitioning\n"
400  << " - increase the minimum coarse size." << std::endl;
401 
402  }
403  }
404 
405  if (isLastLevel) {
406  if (!isOrigLastLevel) {
407  // We did not expect to finish this early so we did request a smoother.
408  // We need a coarse solver instead. Do the magic.
409  level.Release(*smootherFact);
410  level.Request(*coarseFact);
411  }
412 
413  // Do the actual build, if we have any data.
414  // NOTE: this is not a great check, we may want to call Build() regardless.
415  if (!Ac.is_null())
416  coarseFact->Build(level);
417 
418  // Once the dirty deed is done, release stuff. The smoother has already
419  // been released.
420  level.Release(*coarseFact);
421 
422  } else {
423  // isLastLevel = false => isOrigLastLevel = false, meaning that we have
424  // requested the smoother. Now we need to build it and to release it.
425  // We don't need to worry about the coarse solver, as we didn't request it.
426  if (!Ac.is_null())
427  smootherFact->Build(level);
428 
429  level.Release(*smootherFact);
430  }
431 
432  if (isLastLevel == true) {
433  if (isOrigLastLevel == false) {
434  // Earlier in the function, we constructed the next coarse level, and requested data for the that level,
435  // assuming that we are not at the coarsest level. Now, we changed our mind, so we have to release those.
436  Levels_[nextLevelID]->Release(TopRAPFactory(coarseLevelManager, nextLevelManager));
437  }
438  Levels_.resize(nextLevelID);
439  }
440 
441  // I think this is the proper place for graph so that it shows every dependence
442  if (isDumpingEnabled_ && dumpLevel_ > 0 && coarseLevelID == dumpLevel_)
444 
445  if (!isFinestLevel) {
446  // Release the hierarchy data
447  // We release so late to help blocked solvers, as the smoothers for them need A blocks
448  // which we construct in RAPFactory
449  level.Release(coarseRAPFactory);
450  }
451 
452  if (oldRank != -1)
453  SetProcRankVerbose(oldRank);
454 
455  return isLastLevel;
456  }
457 
458  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
460  int numLevels = Levels_.size();
461  TEUCHOS_TEST_FOR_EXCEPTION(levelManagers_.size() != numLevels, Exceptions::RuntimeError,
462  "Hierarchy::SetupRe: " << Levels_.size() << " levels, but " << levelManagers_.size() << " level factory managers");
463 
464  const int startLevel = 0;
465  Clear(startLevel);
466 
467 #ifdef HAVE_MUELU_DEBUG
468  // Reset factories' data used for debugging
469  for (int i = 0; i < numLevels; i++)
470  levelManagers_[i]->ResetDebugData();
471 
472 #endif
473 
474  int levelID;
475  for (levelID = startLevel; levelID < numLevels;) {
476  bool r = Setup(levelID,
477  (levelID != 0 ? levelManagers_[levelID-1] : Teuchos::null),
478  levelManagers_[levelID],
479  (levelID+1 != numLevels ? levelManagers_[levelID+1] : Teuchos::null));
480  levelID++;
481  if (r) break;
482  }
483  // We may construct fewer levels for some reason, make sure we continue
484  // doing that in the future
485  Levels_ .resize(levelID);
486  levelManagers_.resize(levelID);
487 
488  // since the # of levels, etc. may have changed, force re-determination of description during next call to description()
490 
492  }
493 
494  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
495  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Setup(const FactoryManagerBase& manager, int startLevel, int numDesiredLevels) {
496  // Use MueLu::BaseClass::description() to avoid printing "{numLevels = 1}" (numLevels is increasing...)
497  PrintMonitor m0(*this, "Setup (" + this->MueLu::BaseClass::description() + ")", Runtime0);
498 
499  Clear(startLevel);
500 
501  // Check Levels_[startLevel] exists.
502  TEUCHOS_TEST_FOR_EXCEPTION(Levels_.size() <= startLevel, Exceptions::RuntimeError,
503  "MueLu::Hierarchy::Setup(): fine level (" << startLevel << ") does not exist");
504 
505  TEUCHOS_TEST_FOR_EXCEPTION(numDesiredLevels <= 0, Exceptions::RuntimeError,
506  "Constructing non-positive (" << numDesiredLevels << ") number of levels does not make sense.");
507 
508  // Check for fine level matrix A
509  TEUCHOS_TEST_FOR_EXCEPTION(!Levels_[startLevel]->IsAvailable("A"), Exceptions::RuntimeError,
510  "MueLu::Hierarchy::Setup(): fine level (" << startLevel << ") has no matrix A! "
511  "Set fine level matrix A using Level.Set()");
512 
513  RCP<Operator> A = Levels_[startLevel]->template Get<RCP<Operator> >("A");
514  lib_ = A->getDomainMap()->lib();
515 
516  if (IsPrint(Statistics2)) {
517  RCP<Matrix> Amat = rcp_dynamic_cast<Matrix>(A);
518 
519  if (!Amat.is_null()) {
520  RCP<ParameterList> params = rcp(new ParameterList());
521  params->set("printLoadBalancingInfo", true);
522  params->set("printCommInfo", true);
523 
524  GetOStream(Statistics2) << PerfUtils::PrintMatrixInfo(*Amat, "A0", params);
525  } else {
526  GetOStream(Warnings1) << "Fine level operator is not a matrix, statistics are not available" << std::endl;
527  }
528  }
529 
530  RCP<const FactoryManagerBase> rcpmanager = rcpFromRef(manager);
531 
532  const int lastLevel = startLevel + numDesiredLevels - 1;
533  GetOStream(Runtime0) << "Setup loop: startLevel = " << startLevel << ", lastLevel = " << lastLevel
534  << " (stop if numLevels = " << numDesiredLevels << " or Ac.size() < " << maxCoarseSize_ << ")" << std::endl;
535 
536  // Setup multigrid levels
537  int iLevel = 0;
538  if (numDesiredLevels == 1) {
539  iLevel = 0;
540  Setup(startLevel, Teuchos::null, rcpmanager, Teuchos::null); // setup finest==coarsest level (first and last managers are Teuchos::null)
541 
542  } else {
543  bool bIsLastLevel = Setup(startLevel, Teuchos::null, rcpmanager, rcpmanager); // setup finest level (level 0) (first manager is Teuchos::null)
544  if (bIsLastLevel == false) {
545  for (iLevel = startLevel + 1; iLevel < lastLevel; iLevel++) {
546  bIsLastLevel = Setup(iLevel, rcpmanager, rcpmanager, rcpmanager); // setup intermediate levels
547  if (bIsLastLevel == true)
548  break;
549  }
550  if (bIsLastLevel == false)
551  Setup(lastLevel, rcpmanager, rcpmanager, Teuchos::null); // setup coarsest level (last manager is Teuchos::null)
552  }
553  }
554 
555  // TODO: some check like this should be done at the beginning of the routine
556  TEUCHOS_TEST_FOR_EXCEPTION(iLevel != Levels_.size() - 1, Exceptions::RuntimeError,
557  "MueLu::Hierarchy::Setup(): number of level");
558 
559  // TODO: this is not exception safe: manager will still hold default
560  // factories if you exit this function with an exception
561  manager.Clean();
562 
564  }
565 
566  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
568  if (startLevel < GetNumLevels())
569  GetOStream(Runtime0) << "Clearing old data (if any)" << std::endl;
570 
571  for (int iLevel = startLevel; iLevel < GetNumLevels(); iLevel++)
572  Levels_[iLevel]->Clear();
573  }
574 
575  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
577  GetOStream(Runtime0) << "Clearing old data (expert)" << std::endl;
578  for (int iLevel = 0; iLevel < GetNumLevels(); iLevel++)
579  Levels_[iLevel]->ExpertClear();
580  }
581 
582 #if defined(HAVE_MUELU_EXPERIMENTAL) && defined(HAVE_MUELU_ADDITIVE_VARIANT)
583  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
584  ReturnType Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Iterate(const MultiVector& B, MultiVector& X, ConvData conv,
585  bool InitialGuessIsZero, LO startLevel) {
586  LO nIts = conv.maxIts_;
587  MagnitudeType tol = conv.tol_;
588 
589  std::string prefix = this->ShortClassName() + ": ";
590  std::string levelSuffix = " (level=" + toString(startLevel) + ")";
591  std::string levelSuffix1 = " (level=" + toString(startLevel+1) + ")";
592 
593  using namespace Teuchos;
594  RCP<Time> CompTime = Teuchos::TimeMonitor::getNewCounter(prefix + "Computational Time (total)");
595  RCP<Time> Concurrent = Teuchos::TimeMonitor::getNewCounter(prefix + "Concurrent portion");
596  RCP<Time> ApplyR = Teuchos::TimeMonitor::getNewCounter(prefix + "R: Computational Time");
597  RCP<Time> ApplyPbar = Teuchos::TimeMonitor::getNewCounter(prefix + "Pbar: Computational Time");
598  RCP<Time> CompFine = Teuchos::TimeMonitor::getNewCounter(prefix + "Fine: Computational Time");
599  RCP<Time> CompCoarse = Teuchos::TimeMonitor::getNewCounter(prefix + "Coarse: Computational Time");
600  RCP<Time> ApplySum = Teuchos::TimeMonitor::getNewCounter(prefix + "Sum: Computational Time");
601  RCP<Time> Synchronize_beginning = Teuchos::TimeMonitor::getNewCounter(prefix + "Synchronize_beginning");
602  RCP<Time> Synchronize_center = Teuchos::TimeMonitor::getNewCounter(prefix + "Synchronize_center");
603  RCP<Time> Synchronize_end = Teuchos::TimeMonitor::getNewCounter(prefix + "Synchronize_end");
604 
605  RCP<Level> Fine = Levels_[0];
606  RCP<Level> Coarse;
607 
608  RCP<Operator> A = Fine->Get< RCP<Operator> >("A");
609  Teuchos::RCP< const Teuchos::Comm< int > > communicator = A->getDomainMap()->getComm();
610 
611  //Synchronize_beginning->start();
612  //communicator->barrier();
613  //Synchronize_beginning->stop();
614 
615  CompTime->start();
616 
617  SC one = STS::one(), zero = STS::zero();
618 
619  bool zeroGuess = InitialGuessIsZero;
620 
621  // ======= UPFRONT DEFINITION OF COARSE VARIABLES ===========
622 
623  //RCP<const Map> origMap;
624  RCP< Operator > P;
625  RCP< Operator > Pbar;
626  RCP< Operator > R;
627  RCP< MultiVector > coarseRhs, coarseX;
628  RCP< Operator > Ac;
629  RCP<SmootherBase> preSmoo_coarse, postSmoo_coarse;
630  bool emptyCoarseSolve = true;
631  RCP<MultiVector> coarseX_prolonged = MultiVectorFactory::Build(X.getMap(), X.getNumVectors(), true);
632 
633  RCP<const Import> importer;
634 
635  if (Levels_.size() > 1) {
636  Coarse = Levels_[1];
637  if (Coarse->IsAvailable("Importer"))
638  importer = Coarse->Get< RCP<const Import> >("Importer");
639 
640  R = Coarse->Get< RCP<Operator> >("R");
641  P = Coarse->Get< RCP<Operator> >("P");
642 
643 
644  //if(Coarse->IsAvailable("Pbar"))
645  Pbar = Coarse->Get< RCP<Operator> >("Pbar");
646 
647  coarseRhs = MultiVectorFactory::Build(R->getRangeMap(), B.getNumVectors(), true);
648 
649  Ac = Coarse->Get< RCP< Operator > >("A");
650 
651  ApplyR->start();
652  R->apply(B, *coarseRhs, Teuchos::NO_TRANS, one, zero);
653  //P->apply(B, *coarseRhs, Teuchos::TRANS, one, zero);
654  ApplyR->stop();
655 
656  if (doPRrebalance_ || importer.is_null()) {
657  coarseX = MultiVectorFactory::Build(coarseRhs->getMap(), X.getNumVectors(), true);
658 
659  } else {
660 
661  RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : import (total)" , Timings0));
662  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : import" + levelSuffix1, Timings0));
663 
664  // Import: range map of R --> domain map of rebalanced Ac (before subcomm replacement)
665  RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getTargetMap(), coarseRhs->getNumVectors());
666  coarseTmp->doImport(*coarseRhs, *importer, Xpetra::INSERT);
667  coarseRhs.swap(coarseTmp);
668 
669  coarseX = MultiVectorFactory::Build(importer->getTargetMap(), X.getNumVectors(), true);
670  }
671 
672  if (Coarse->IsAvailable("PreSmoother"))
673  preSmoo_coarse = Coarse->Get< RCP<SmootherBase> >("PreSmoother");
674  if (Coarse->IsAvailable("PostSmoother"))
675  postSmoo_coarse = Coarse->Get< RCP<SmootherBase> >("PostSmoother");
676  }
677 
678  // ==========================================================
679 
680 
681  MagnitudeType prevNorm = STS::magnitude(STS::one()), curNorm = STS::magnitude(STS::one());
682  rate_ = 1.0;
683 
684  for (LO i = 1; i <= nIts; i++) {
685 #ifdef HAVE_MUELU_DEBUG
686  if (A->getDomainMap()->isCompatible(*(X.getMap())) == false) {
687  std::ostringstream ss;
688  ss << "Level " << startLevel << ": level A's domain map is not compatible with X";
689  throw Exceptions::Incompatible(ss.str());
690  }
691 
692  if (A->getRangeMap()->isCompatible(*(B.getMap())) == false) {
693  std::ostringstream ss;
694  ss << "Level " << startLevel << ": level A's range map is not compatible with B";
695  throw Exceptions::Incompatible(ss.str());
696  }
697 #endif
698  }
699 
700  bool emptyFineSolve = true;
701 
702  RCP< MultiVector > fineX;
703  fineX = MultiVectorFactory::Build(X.getMap(), X.getNumVectors(), true);
704 
705  //Synchronize_center->start();
706  //communicator->barrier();
707  //Synchronize_center->stop();
708 
709  Concurrent->start();
710 
711  // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
712  if (Fine->IsAvailable("PreSmoother")) {
713  RCP<SmootherBase> preSmoo = Fine->Get< RCP<SmootherBase> >("PreSmoother");
714  CompFine->start();
715  preSmoo->Apply(*fineX, B, zeroGuess);
716  CompFine->stop();
717  emptyFineSolve = false;
718  }
719  if (Fine->IsAvailable("PostSmoother")) {
720  RCP<SmootherBase> postSmoo = Fine->Get< RCP<SmootherBase> >("PostSmoother");
721  CompFine->start();
722  postSmoo->Apply(*fineX, B, zeroGuess);
723  CompFine->stop();
724 
725  emptyFineSolve = false;
726  }
727  if (emptyFineSolve == true) {
728  GetOStream(Warnings1) << "No fine grid smoother" << std::endl;
729  // Fine grid smoother is identity
730  fineX->update(one, B, zero);
731  }
732 
733  if (Levels_.size() > 1) {
734  // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
735  if (Coarse->IsAvailable("PreSmoother")) {
736  CompCoarse->start();
737  preSmoo_coarse->Apply(*coarseX, *coarseRhs, zeroGuess);
738  CompCoarse->stop();
739  emptyCoarseSolve = false;
740 
741  }
742  if (Coarse->IsAvailable("PostSmoother")) {
743  CompCoarse->start();
744  postSmoo_coarse->Apply(*coarseX, *coarseRhs, zeroGuess);
745  CompCoarse->stop();
746  emptyCoarseSolve = false;
747 
748  }
749  if (emptyCoarseSolve == true) {
750  GetOStream(Warnings1) << "No coarse grid solver" << std::endl;
751  // Coarse operator is identity
752  coarseX->update(one, *coarseRhs, zero);
753  }
754  Concurrent->stop();
755  //Synchronize_end->start();
756  //communicator->barrier();
757  //Synchronize_end->stop();
758 
759  if (!doPRrebalance_ && !importer.is_null()) {
760  RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : export (total)" , Timings0));
761  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : export" + levelSuffix1, Timings0));
762 
763  // Import: range map of rebalanced Ac (before subcomm replacement) --> domain map of P
764  RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getSourceMap(), coarseX->getNumVectors());
765  coarseTmp->doExport(*coarseX, *importer, Xpetra::INSERT);
766  coarseX.swap(coarseTmp);
767  }
768 
769  ApplyPbar->start();
770  Pbar->apply(*coarseX, *coarseX_prolonged, Teuchos::NO_TRANS, one, zero);
771  ApplyPbar->stop();
772  }
773 
774  ApplySum->start();
775  X.update(1.0, *fineX, 1.0, *coarseX_prolonged, 0.0);
776  ApplySum->stop();
777 
778  CompTime->stop();
779 
780  //communicator->barrier();
781 
782  return (tol > 0 ? Unconverged : Undefined);
783 }
784 #else
785  // ---------------------------------------- Iterate -------------------------------------------------------
786  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
788  bool InitialGuessIsZero, LO startLevel) {
789  LO nIts = conv.maxIts_;
790  MagnitudeType tol = conv.tol_;
791 
792  // These timers work as follows. "iterateTime" records total time spent in
793  // iterate. "levelTime" records time on a per level basis. The label is
794  // crafted to mimic the per-level messages used in Monitors. Note that a
795  // given level is timed with a TimeMonitor instead of a Monitor or
796  // SubMonitor. This is mainly because I want to time each level
797  // separately, and Monitors/SubMonitors print "(total) xx yy zz" ,
798  // "(sub,total) xx yy zz", respectively, which is subject to
799  // misinterpretation. The per-level TimeMonitors are stopped/started
800  // manually before/after a recursive call to Iterate. A side artifact to
801  // this approach is that the counts for intermediate level timers are twice
802  // the counts for the finest and coarsest levels.
803  std::string prefix = this->ShortClassName() + ": ";
804  std::string levelSuffix = " (level=" + toString(startLevel) + ")";
805  std::string levelSuffix1 = " (level=" + toString(startLevel+1) + ")";
806 
807  RCP<Monitor> iterateTime;
808  RCP<TimeMonitor> iterateTime1;
809  if (startLevel == 0)
810  iterateTime = rcp(new Monitor(*this, "Solve", (nIts == 1) ? None : Runtime0, Timings0));
811  else
812  iterateTime1 = rcp(new TimeMonitor(*this, prefix + "Solve (total, level=" + toString(startLevel) + ")", Timings0));
813 
814  std::string iterateLevelTimeLabel = prefix + "Solve" + levelSuffix;
815  RCP<TimeMonitor> iterateLevelTime = rcp(new TimeMonitor(*this, iterateLevelTimeLabel, Timings0));
816 
817  bool zeroGuess = InitialGuessIsZero;
818 
819  RCP<Level> Fine = Levels_[startLevel];
820  RCP<Operator> A = Fine->Get< RCP<Operator> >("A");
821  using namespace Teuchos;
822  RCP<Time> CompCoarse = Teuchos::TimeMonitor::getNewCounter(prefix + "Coarse: Computational Time");
823 
824  if (A.is_null()) {
825  // This processor does not have any data for this process on coarser
826  // levels. This can only happen when there are multiple processors and
827  // we use repartitioning.
828  return Undefined;
829  }
830 
831  // Print residual information before iterating
832  MagnitudeType prevNorm = STS::magnitude(STS::one()), curNorm = STS::magnitude(STS::one());
833  rate_ = 1.0;
834  if (startLevel == 0 && !isPreconditioner_ &&
835  (IsPrint(Statistics1) || tol > 0)) {
836  // We calculate the residual only if we want to print it out, or if we
837  // want to stop once we achive the tolerance
838  Teuchos::Array<MagnitudeType> rn;
839  rn = Utilities::ResidualNorm(*A, X, B);
840 
841  if (tol > 0) {
842  bool passed = true;
843  for (LO k = 0; k < rn.size(); k++)
844  if (rn[k] >= tol)
845  passed = false;
846 
847  if (passed)
848  return Converged;
849  }
850 
851  if (IsPrint(Statistics1))
852  GetOStream(Statistics1) << "iter: "
853  << std::setiosflags(std::ios::left)
854  << std::setprecision(3) << 0 // iter 0
855  << " residual = "
856  << std::setprecision(10) << rn
857  << std::endl;
858  }
859 
860  SC one = STS::one(), zero = STS::zero();
861  for (LO i = 1; i <= nIts; i++) {
862 #ifdef HAVE_MUELU_DEBUG
863 #if 0 // TODO fix me
864  if (A->getDomainMap()->isCompatible(*(X.getMap())) == false) {
865  std::ostringstream ss;
866  ss << "Level " << startLevel << ": level A's domain map is not compatible with X";
867  throw Exceptions::Incompatible(ss.str());
868  }
869 
870  if (A->getRangeMap()->isCompatible(*(B.getMap())) == false) {
871  std::ostringstream ss;
872  ss << "Level " << startLevel << ": level A's range map is not compatible with B";
873  throw Exceptions::Incompatible(ss.str());
874  }
875 #endif
876 #endif
877 
878  if (startLevel == as<LO>(Levels_.size())-1) {
879  // On the coarsest level, we do either smoothing (if defined) or a direct solve.
880  RCP<TimeMonitor> CLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : coarse" + levelSuffix, Timings0));
881 
882  bool emptySolve = true;
883 
884  // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
885  if (Fine->IsAvailable("PreSmoother")) {
886  RCP<SmootherBase> preSmoo = Fine->Get< RCP<SmootherBase> >("PreSmoother");
887  CompCoarse->start();
888  preSmoo->Apply(X, B, zeroGuess);
889  CompCoarse->stop();
890  zeroGuess = false;
891  emptySolve = false;
892  }
893  if (Fine->IsAvailable("PostSmoother")) {
894  RCP<SmootherBase> postSmoo = Fine->Get< RCP<SmootherBase> >("PostSmoother");
895  CompCoarse->start();
896  postSmoo->Apply(X, B, zeroGuess);
897  CompCoarse->stop();
898  emptySolve = false;
899  }
900  if (emptySolve == true) {
901  GetOStream(Warnings1) << "No coarse grid solver" << std::endl;
902  // Coarse operator is identity
903  X.update(one, B, zero);
904  }
905 
906  } else {
907  // On intermediate levels, we do cycles
908  RCP<Level> Coarse = Levels_[startLevel+1];
909  {
910  // ============== PRESMOOTHING ==============
911  RCP<TimeMonitor> STime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing (total)" , Timings0));
912  RCP<TimeMonitor> SLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing" + levelSuffix, Timings0));
913 
914  if (Fine->IsAvailable("PreSmoother")) {
915  RCP<SmootherBase> preSmoo = Fine->Get< RCP<SmootherBase> >("PreSmoother");
916  preSmoo->Apply(X, B, zeroGuess);
917  } else {
918  GetOStream(Warnings1) << "Level " << startLevel << ": No PreSmoother!" << std::endl;
919  }
920  }
921 
922  RCP<MultiVector> residual;
923  {
924  RCP<TimeMonitor> ATime = rcp(new TimeMonitor(*this, prefix + "Solve : residual calculation (total)" , Timings0));
925  RCP<TimeMonitor> ALevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : residual calculation" + levelSuffix, Timings0));
926  residual = Utilities::Residual(*A, X, B);
927  }
928 
929  RCP<Operator> P = Coarse->Get< RCP<Operator> >("P");
930  if (Coarse->IsAvailable("Pbar"))
931  P = Coarse->Get< RCP<Operator> >("Pbar");
932 
933  RCP<MultiVector> coarseRhs, coarseX;
934  const bool initializeWithZeros = true;
935  {
936  // ============== RESTRICTION ==============
937  RCP<TimeMonitor> RTime = rcp(new TimeMonitor(*this, prefix + "Solve : restriction (total)" , Timings0));
938  RCP<TimeMonitor> RLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : restriction" + levelSuffix, Timings0));
939 
940  if (implicitTranspose_) {
941  coarseRhs = MultiVectorFactory::Build(P->getDomainMap(), X.getNumVectors(), !initializeWithZeros);
942  P->apply(*residual, *coarseRhs, Teuchos::TRANS, one, zero);
943 
944  } else {
945  RCP<Operator> R = Coarse->Get< RCP<Operator> >("R");
946  coarseRhs = MultiVectorFactory::Build(R->getRangeMap(), X.getNumVectors(), !initializeWithZeros);
947  R->apply(*residual, *coarseRhs, Teuchos::NO_TRANS, one, zero);
948  }
949  }
950 
951  RCP<const Import> importer;
952  if (Coarse->IsAvailable("Importer"))
953  importer = Coarse->Get< RCP<const Import> >("Importer");
954 
955  if (doPRrebalance_ || importer.is_null()) {
956  coarseX = MultiVectorFactory::Build(coarseRhs->getMap(), X.getNumVectors(), initializeWithZeros);
957 
958  } else {
959  RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : import (total)" , Timings0));
960  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : import" + levelSuffix1, Timings0));
961 
962  // Import: range map of R --> domain map of rebalanced Ac (before subcomm replacement)
963  RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getTargetMap(), coarseRhs->getNumVectors());
964  coarseTmp->doImport(*coarseRhs, *importer, Xpetra::INSERT);
965  coarseRhs.swap(coarseTmp);
966 
967  coarseX = MultiVectorFactory::Build(importer->getTargetMap(), X.getNumVectors(), initializeWithZeros);
968  }
969 
970  RCP<Operator> Ac = Coarse->Get< RCP<Operator> >("A");
971  if (!Ac.is_null()) {
972  RCP<const Map> origXMap = coarseX->getMap();
973 
974  // Replace maps with maps with a subcommunicator
975  coarseRhs->replaceMap(Ac->getRangeMap());
976  coarseX ->replaceMap(Ac->getDomainMap());
977 
978  {
979  iterateLevelTime = Teuchos::null; // stop timing this level
980 
981  Iterate(*coarseRhs, *coarseX, 1, true, startLevel+1);
982  // ^^ zero initial guess
983  if (Cycle_ == WCYCLE)
984  Iterate(*coarseRhs, *coarseX, 1, false, startLevel+1);
985  // ^^ nonzero initial guess
986 
987  iterateLevelTime = rcp(new TimeMonitor(*this, iterateLevelTimeLabel)); // restart timing this level
988  }
989  coarseX->replaceMap(origXMap);
990  }
991 
992  if (!doPRrebalance_ && !importer.is_null()) {
993  RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : export (total)" , Timings0));
994  RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : export" + levelSuffix1, Timings0));
995 
996  // Import: range map of rebalanced Ac (before subcomm replacement) --> domain map of P
997  RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getSourceMap(), coarseX->getNumVectors());
998  coarseTmp->doExport(*coarseX, *importer, Xpetra::INSERT);
999  coarseX.swap(coarseTmp);
1000  }
1001 
1002  // Update X += P * coarseX
1003  // Note that due to what may be round-off error accumulation, use of the fused kernel
1004  // P->apply(*coarseX, X, Teuchos::NO_TRANS, one, one);
1005  // can in some cases result in slightly higher iteration counts.
1006  RCP<MultiVector> correction = MultiVectorFactory::Build(X.getMap(), X.getNumVectors(),false);
1007  {
1008  // ============== PROLONGATION ==============
1009  RCP<TimeMonitor> PTime = rcp(new TimeMonitor(*this, prefix + "Solve : prolongation (total)" , Timings0));
1010  RCP<TimeMonitor> PLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : prolongation" + levelSuffix, Timings0));
1011  P->apply(*coarseX, *correction, Teuchos::NO_TRANS, one, zero);
1012  }
1013  X.update(scalingFactor_, *correction, one);
1014 
1015  {
1016  // ============== POSTSMOOTHING ==============
1017  RCP<TimeMonitor> STime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing (total)" , Timings0));
1018  RCP<TimeMonitor> SLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing" + levelSuffix, Timings0));
1019 
1020  if (Fine->IsAvailable("PostSmoother")) {
1021  RCP<SmootherBase> postSmoo = Fine->Get< RCP<SmootherBase> >("PostSmoother");
1022  postSmoo->Apply(X, B, false);
1023 
1024  } else {
1025  GetOStream(Warnings1) << "Level " << startLevel << ": No PostSmoother!" << std::endl;
1026  }
1027  }
1028  }
1029  zeroGuess = false;
1030 
1031  if (startLevel == 0 && !isPreconditioner_ &&
1032  (IsPrint(Statistics1) || tol > 0)) {
1033  // We calculate the residual only if we want to print it out, or if we
1034  // want to stop once we achive the tolerance
1035  Teuchos::Array<MagnitudeType> rn;
1036  rn = Utilities::ResidualNorm(*A, X, B);
1037 
1038  prevNorm = curNorm;
1039  curNorm = rn[0];
1040  rate_ = as<MagnitudeType>(curNorm / prevNorm);
1041 
1042  if (tol > 0) {
1043  bool passed = true;
1044  for (LO k = 0; k < rn.size(); k++)
1045  if (rn[k] >= tol)
1046  passed = false;
1047 
1048  if (passed)
1049  return Converged;
1050  }
1051 
1052  if (IsPrint(Statistics1))
1053  GetOStream(Statistics1) << "iter: "
1054  << std::setiosflags(std::ios::left)
1055  << std::setprecision(3) << i
1056  << " residual = "
1057  << std::setprecision(10) << rn
1058  << std::endl;
1059  }
1060  }
1061  return (tol > 0 ? Unconverged : Undefined);
1062  }
1063 #endif
1064 
1065 
1066  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1067  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(const LO& start, const LO& end, const std::string &suffix) {
1068  LO startLevel = (start != -1 ? start : 0);
1069  LO endLevel = (end != -1 ? end : Levels_.size()-1);
1070 
1071  TEUCHOS_TEST_FOR_EXCEPTION(startLevel > endLevel, Exceptions::RuntimeError,
1072  "MueLu::Hierarchy::Write : startLevel must be <= endLevel");
1073 
1074  TEUCHOS_TEST_FOR_EXCEPTION(startLevel < 0 || endLevel >= Levels_.size(), Exceptions::RuntimeError,
1075  "MueLu::Hierarchy::Write bad start or end level");
1076 
1077  for (LO i = startLevel; i < endLevel + 1; i++) {
1078  RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Levels_[i]-> template Get< RCP< Operator> >("A")), P, R;
1079  if (i > 0) {
1080  P = rcp_dynamic_cast<Matrix>(Levels_[i]-> template Get< RCP< Operator> >("P"));
1081  if (!implicitTranspose_)
1082  R = rcp_dynamic_cast<Matrix>(Levels_[i]-> template Get< RCP< Operator> >("R"));
1083  }
1084 
1085  if (!A.is_null()) Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("A_" + toString(i) + suffix + ".m", *A);
1086  if (!P.is_null()) {
1087  Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("P_" + toString(i) + suffix + ".m", *P);
1088  }
1089  if (!R.is_null()) {
1090  Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("R_" + toString(i) + suffix + ".m", *R);
1091  }
1092  }
1093  }
1094 
1095  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1096  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Keep(const std::string & ename, const FactoryBase* factory) {
1097  for (Array<RCP<Level> >::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1098  (*it)->Keep(ename, factory);
1099  }
1100 
1101  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1102  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Delete(const std::string& ename, const FactoryBase* factory) {
1103  for (Array<RCP<Level> >::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1104  (*it)->Delete(ename, factory);
1105  }
1106 
1107  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1108  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::AddKeepFlag(const std::string & ename, const FactoryBase* factory, KeepType keep) {
1109  for (Array<RCP<Level> >::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1110  (*it)->AddKeepFlag(ename, factory, keep);
1111  }
1112 
1113  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1115  for (Array<RCP<Level> >::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1116  (*it)->RemoveKeepFlag(ename, factory, keep);
1117  }
1118 
1119  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1121  if ( description_.empty() )
1122  {
1123  std::ostringstream out;
1124  out << BaseClass::description();
1125  out << "{#levels = " << GetGlobalNumLevels() << ", complexity = " << GetOperatorComplexity() << "}";
1126  description_ = out.str();
1127  }
1128  return description_;
1129  }
1130 
1131  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1132  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::describe(Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel tVerbLevel) const {
1133  describe(out, toMueLuVerbLevel(tVerbLevel));
1134  }
1135 
1136  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1137  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::describe(Teuchos::FancyOStream& out, const VerbLevel verbLevel) const {
1138  RCP<Operator> A0 = Levels_[0]->template Get<RCP<Operator> >("A");
1139  RCP<const Teuchos::Comm<int> > comm = A0->getDomainMap()->getComm();
1140 
1141  int numLevels = GetNumLevels();
1142  RCP<Operator> Ac = Levels_[numLevels-1]->template Get<RCP<Operator> >("A");
1143  if (Ac.is_null()) {
1144  // It may happen that we do repartition on the last level, but the matrix
1145  // is small enough to satisfy "max coarse size" requirement. Then, even
1146  // though we have the level, the matrix would be null on all but one processors
1147  numLevels--;
1148  }
1149  int root = comm->getRank();
1150 
1151 #ifdef HAVE_MPI
1152  int smartData = numLevels*comm->getSize() + comm->getRank(), maxSmartData;
1153  reduceAll(*comm, Teuchos::REDUCE_MAX, smartData, Teuchos::ptr(&maxSmartData));
1154  root = maxSmartData % comm->getSize();
1155 #endif
1156 
1157  // Compute smoother complexity, if needed
1158  double smoother_comp =-1.0;
1159  if (verbLevel & (Statistics0 | Test))
1160  smoother_comp = GetSmootherComplexity();
1161 
1162  std::string outstr;
1163  if (comm->getRank() == root && verbLevel & (Statistics0 | Test)) {
1164  std::vector<Xpetra::global_size_t> nnzPerLevel;
1165  std::vector<Xpetra::global_size_t> rowsPerLevel;
1166  std::vector<int> numProcsPerLevel;
1167  bool aborted = false;
1168  for (int i = 0; i < numLevels; i++) {
1169  TEUCHOS_TEST_FOR_EXCEPTION(!(Levels_[i]->IsAvailable("A")) , Exceptions::RuntimeError,
1170  "Operator A is not available on level " << i);
1171 
1172  RCP<Operator> A = Levels_[i]->template Get<RCP<Operator> >("A");
1173  TEUCHOS_TEST_FOR_EXCEPTION(A.is_null(), Exceptions::RuntimeError,
1174  "Operator A on level " << i << " is null.");
1175 
1176  RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
1177  if (Am.is_null()) {
1178  GetOStream(Warnings0) << "Some level operators are not matrices, statistics calculation aborted" << std::endl;
1179  aborted = true;
1180  break;
1181  }
1182 
1183  Xpetra::global_size_t nnz = Am->getGlobalNumEntries();
1184  nnzPerLevel .push_back(nnz);
1185  rowsPerLevel .push_back(Am->getGlobalNumRows());
1186  numProcsPerLevel.push_back(Am->getRowMap()->getComm()->getSize());
1187  }
1188 
1189  if (!aborted) {
1190  std::ostringstream oss;
1191  oss << "\n--------------------------------------------------------------------------------\n" <<
1192  "--- Multigrid Summary ---\n"
1193  "--------------------------------------------------------------------------------" << std::endl;
1194  oss << "Number of levels = " << numLevels << std::endl;
1195  oss << "Operator complexity = " << std::setprecision(2) << std::setiosflags(std::ios::fixed)
1196  << GetOperatorComplexity() << std::endl;
1197 
1198  if(smoother_comp!=-1.0) {
1199  oss << "Smoother complexity = " << std::setprecision(2) << std::setiosflags(std::ios::fixed)
1200  << smoother_comp << std::endl;
1201  }
1202 
1203  switch (Cycle_) {
1204  case VCYCLE:
1205  oss << "Cycle type = V" << std::endl;
1206  break;
1207  case WCYCLE:
1208  oss << "Cycle type = W" << std::endl;
1209  break;
1210  default:
1211  break;
1212  };
1213  oss << std::endl;
1214 
1215  Xpetra::global_size_t tt = rowsPerLevel[0];
1216  int rowspacer = 2; while (tt != 0) { tt /= 10; rowspacer++; }
1217  tt = nnzPerLevel[0];
1218  int nnzspacer = 2; while (tt != 0) { tt /= 10; nnzspacer++; }
1219  tt = numProcsPerLevel[0];
1220  int npspacer = 2; while (tt != 0) { tt /= 10; npspacer++; }
1221  oss << "level " << std::setw(rowspacer) << " rows " << std::setw(nnzspacer) << " nnz " << " nnz/row" << std::setw(npspacer) << " c ratio" << " procs" << std::endl;
1222  for (size_t i = 0; i < nnzPerLevel.size(); ++i) {
1223  oss << " " << i << " ";
1224  oss << std::setw(rowspacer) << rowsPerLevel[i];
1225  oss << std::setw(nnzspacer) << nnzPerLevel[i];
1226  oss << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1227  oss << std::setw(9) << as<double>(nnzPerLevel[i]) / rowsPerLevel[i];
1228  if (i) oss << std::setw(9) << as<double>(rowsPerLevel[i-1])/rowsPerLevel[i];
1229  else oss << std::setw(9) << " ";
1230  oss << " " << std::setw(npspacer) << numProcsPerLevel[i] << std::endl;
1231  }
1232  oss << std::endl;
1233  for (int i = 0; i < GetNumLevels(); ++i) {
1234  RCP<SmootherBase> preSmoo, postSmoo;
1235  if (Levels_[i]->IsAvailable("PreSmoother"))
1236  preSmoo = Levels_[i]->template Get< RCP<SmootherBase> >("PreSmoother");
1237  if (Levels_[i]->IsAvailable("PostSmoother"))
1238  postSmoo = Levels_[i]->template Get< RCP<SmootherBase> >("PostSmoother");
1239 
1240  if (preSmoo != null && preSmoo == postSmoo)
1241  oss << "Smoother (level " << i << ") both : " << preSmoo->description() << std::endl;
1242  else {
1243  oss << "Smoother (level " << i << ") pre : "
1244  << (preSmoo != null ? preSmoo->description() : "no smoother") << std::endl;
1245  oss << "Smoother (level " << i << ") post : "
1246  << (postSmoo != null ? postSmoo->description() : "no smoother") << std::endl;
1247  }
1248 
1249  oss << std::endl;
1250  }
1251 
1252  outstr = oss.str();
1253  }
1254  }
1255 
1256 #ifdef HAVE_MPI
1257  RCP<const Teuchos::MpiComm<int> > mpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm);
1258  MPI_Comm rawComm = (*mpiComm->getRawMpiComm())();
1259 
1260  int strLength = outstr.size();
1261  MPI_Bcast(&strLength, 1, MPI_INT, root, rawComm);
1262  if (comm->getRank() != root)
1263  outstr.resize(strLength);
1264  MPI_Bcast(&outstr[0], strLength, MPI_CHAR, root, rawComm);
1265 #endif
1266 
1267  out << outstr;
1268  }
1269 
1270  // NOTE: at some point this should be replaced by a friend operator <<
1271  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1272  void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(std::ostream& out, const VerbLevel verbLevel) const {
1273  Teuchos::OSTab tab2(out);
1274  for (int i = 0; i < GetNumLevels(); ++i)
1275  Levels_[i]->print(out, verbLevel);
1276  }
1277 
1278  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1280  isPreconditioner_ = flag;
1281  }
1282 
1283  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1285  if (GetProcRankVerbose() != 0)
1286  return;
1287 #if defined(HAVE_MUELU_BOOST) && defined(HAVE_MUELU_BOOST_FOR_REAL) && defined(BOOST_VERSION) && (BOOST_VERSION >= 104400)
1288  BoostGraph graph;
1289 
1290  BoostProperties dp;
1291  dp.property("label", boost::get(boost::vertex_name, graph));
1292  dp.property("id", boost::get(boost::vertex_index, graph));
1293  dp.property("label", boost::get(boost::edge_name, graph));
1294  dp.property("color", boost::get(boost::edge_color, graph));
1295 
1296  // create local maps
1297  std::map<const FactoryBase*, BoostVertex> vindices;
1298  typedef std::map<std::pair<BoostVertex,BoostVertex>, std::string> emap; emap edges;
1299 
1300  for (int i = dumpLevel_; i <= dumpLevel_+1 && i < GetNumLevels(); i++) {
1301  edges.clear();
1302  Levels_[i]->UpdateGraph(vindices, edges, dp, graph);
1303 
1304  for (emap::const_iterator eit = edges.begin(); eit != edges.end(); eit++) {
1305  std::pair<BoostEdge, bool> boost_edge = boost::add_edge(eit->first.first, eit->first.second, graph);
1306  boost::put("label", dp, boost_edge.first, eit->second);
1307  if (i == dumpLevel_)
1308  boost::put("color", dp, boost_edge.first, std::string("red"));
1309  else
1310  boost::put("color", dp, boost_edge.first, std::string("blue"));
1311  }
1312  }
1313 
1314  // add legend
1315  std::ostringstream legend;
1316  legend << "< <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\"> \
1317  <TR><TD COLSPAN=\"2\">Legend</TD></TR> \
1318  <TR><TD><FONT color=\"red\">Level " << dumpLevel_ << "</FONT></TD><TD><FONT color=\"blue\">Level " << dumpLevel_+1 << "</FONT></TD></TR> \
1319  </TABLE> >";
1320  BoostVertex boost_vertex = boost::add_vertex(graph);
1321  boost::put("label", dp, boost_vertex, legend.str());
1322 
1323  std::ofstream out(dumpFile_.c_str());
1324  boost::write_graphviz_dp(out, graph, dp, std::string("id"));
1325 #else
1326  GetOStream(Errors) << "Dependency graph output requires boost and MueLu_ENABLE_Boost_for_real" << std::endl;
1327 #endif
1328  }
1329 
1330  // Enforce that coordinate vector's map is consistent with that of A
1331  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1333  RCP<Operator> Ao = level.Get<RCP<Operator> >("A");
1334  RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Ao);
1335  if (A.is_null()) {
1336  GetOStream(Warnings1) << "Hierarchy::ReplaceCoordinateMap: operator is not a matrix, skipping..." << std::endl;
1337  return;
1338  }
1339  if(Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A) != Teuchos::null) {
1340  GetOStream(Warnings1) << "Hierarchy::ReplaceCoordinateMap: operator is a BlockedCrsMatrix, skipping..." << std::endl;
1341  return;
1342  }
1343 
1344  typedef Xpetra::MultiVector<double,LO,GO,NO> xdMV;
1345 
1346  RCP<xdMV> coords = level.Get<RCP<xdMV> >("Coordinates");
1347 
1348  if (A->getRowMap()->isSameAs(*(coords->getMap()))) {
1349  GetOStream(Warnings1) << "Hierarchy::ReplaceCoordinateMap: matrix and coordinates maps are same, skipping..." << std::endl;
1350  return;
1351  }
1352 
1353  if (A->IsView("stridedMaps") && rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps")) != Teuchos::null) {
1354  RCP<const StridedMap> stridedRowMap = rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps"));
1355 
1356  // It is better to through an exceptions if maps may be inconsistent, than to ignore it and experience unfathomable breakdowns
1357  TEUCHOS_TEST_FOR_EXCEPTION(stridedRowMap->getStridedBlockId() != -1 || stridedRowMap->getOffset() != 0,
1358  Exceptions::RuntimeError, "Hierarchy::ReplaceCoordinateMap: nontrivial maps (block id = " << stridedRowMap->getStridedBlockId()
1359  << ", offset = " << stridedRowMap->getOffset() << ")");
1360  }
1361 
1362  GetOStream(Runtime1) << "Replacing coordinate map" << std::endl;
1363 
1364  size_t blkSize = A->GetFixedBlockSize();
1365 
1366  RCP<const Map> nodeMap = A->getRowMap();
1367  if (blkSize > 1) {
1368  // Create a nodal map, as coordinates have not been expanded to a DOF map yet.
1369  RCP<const Map> dofMap = A->getRowMap();
1370  GO indexBase = dofMap->getIndexBase();
1371  size_t numLocalDOFs = dofMap->getNodeNumElements();
1372  TEUCHOS_TEST_FOR_EXCEPTION(numLocalDOFs % blkSize, Exceptions::RuntimeError,
1373  "Hierarchy::ReplaceCoordinateMap: block size (" << blkSize << ") is incompatible with the number of local dofs in a row map (" << numLocalDOFs);
1374  ArrayView<const GO> GIDs = dofMap->getNodeElementList();
1375 
1376  Array<GO> nodeGIDs(numLocalDOFs/blkSize);
1377  for (size_t i = 0; i < numLocalDOFs; i += blkSize)
1378  nodeGIDs[i/blkSize] = (GIDs[i] - indexBase)/blkSize + indexBase;
1379 
1380  Xpetra::global_size_t INVALID = Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid();
1381  nodeMap = MapFactory::Build(dofMap->lib(), INVALID, nodeGIDs(), indexBase, dofMap->getComm());
1382  } else {
1383  // blkSize == 1
1384  // Check whether the length of vectors fits to the size of A
1385  // If yes, make sure that the maps are matching
1386  // If no, throw a warning but do not touch the Coordinates
1387  if(coords->getLocalLength() != A->getRowMap()->getNodeNumElements()) {
1388  GetOStream(Warnings) << "Coordinate vector does not match row map of matrix A!" << std::endl;
1389  return;
1390  }
1391  }
1392 
1393  Array<ArrayView<const double> > coordDataView;
1394  std::vector<ArrayRCP<const double> > coordData;
1395  for (size_t i = 0; i < coords->getNumVectors(); i++) {
1396  coordData.push_back(coords->getData(i));
1397  coordDataView.push_back(coordData[i]());
1398  }
1399 
1400  RCP<xdMV> newCoords = Xpetra::MultiVectorFactory<double,LO,GO,NO>::Build(nodeMap, coordDataView(), coords->getNumVectors());
1401  level.Set("Coordinates", newCoords);
1402  }
1403 
1404 } //namespace MueLu
1405 
1406 #endif // MUELU_HIERARCHY_DEF_HPP
Important warning messages (one line)
void IsPreconditioner(const bool flag)
RCP< Level > & GetPreviousLevel()
Previous level.
static void SetRandomSeed(const Teuchos::Comm< int > &comm)
High level timing information (use Teuchos::TimeMonitor::summarize() to print)
double GetSmootherComplexity() 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->Get< RCP<Matrix> >("A", factory) if factory == NULL => use default factory.
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.
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
Hierarchy()
Default constructor.
virtual std::string ShortClassName() const
Return the class name of the object, without template parameters and without namespace.
void Release(const FactoryBase &factory)
Decrement the storage counter for all the inputs of a factory.
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
void AddLevel(const RCP< Level > &level)
Add a level at the end of the hierarchy.
short KeepType
Print more statistics.
void AddNewLevel()
Add a new level at the end of the hierarchy.
VerbLevel toMueLuVerbLevel(const Teuchos::EVerbosityLevel verbLevel)
One-liner description of what is happening.
static Xpetra::global_size_t GetDefaultMaxCoarseSize()
void Clear(int startLevel=0)
Clear impermanent data from previous setup.
Namespace for MueLu classes and methods.
Exception throws to report incompatible objects (like maps).
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
Integrates Teuchos::TimeMonitor with MueLu verbosity system.
Print skeleton for the run, i.e. factory calls and used parameters.
int SetProcRankVerbose(int procRank) const
Set proc rank used for printing.
MagnitudeType rate_
Convergece rate.
void ReplaceCoordinateMap(Level &level)
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)
int GetLevelID() const
Return level number.
Definition: MueLu_Level.cpp:76
void print(std::ostream &out=std::cout, const VerbLevel verbLevel=(MueLu::Parameters|MueLu::Statistics0)) const
Additional warnings.
Base class for factories (e.g., R, P, and A_coarse).
Print statistics that do not involve significant additional computation.
Xpetra::UnderlyingLib lib_
static RCP< Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &RHS)
static CycleType GetDefaultCycle()
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:99
Class that provides default factories within Needs class.
RCP< const Teuchos::Comm< int > > GetComm() const
int GetProcRankVerbose() const
Get proc rank used for printing. Do not use this information for any other purpose.
void RemoveKeepFlag(const std::string &ename, const FactoryBase *factory, KeepType keep=MueLu::All)
Call Level::RemoveKeepFlag for each level of the Hierarchy.
int GetGlobalNumLevels() const
void CheckLevel(Level &level, int levelID)
Helper function.
Xpetra::UnderlyingLib lib()
static bool GetDefaultImplicitTranspose()
void describe(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the Hierarchy with some verbosity level to a FancyOStream object.
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
double GetOperatorComplexity() const
Data struct for defining stopping criteria of multigrid iteration.
static Teuchos::Array< Magnitude > ResidualNorm(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &X, const Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &RHS)
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.
Array< RCP< Level > > Levels_
Container for Level objects.
static bool GetDefaultPRrebalance()
VerbLevel GetVerbLevel() const
Get the verbosity level.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need&#39;s value has been saved.
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)
Print all warning messages.
ReturnType Iterate(const MultiVector &B, MultiVector &X, ConvData conv=ConvData(), bool InitialGuessIsZero=false, LO startLevel=0)
Apply the multigrid preconditioner.
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.
bool isDumpingEnabled_
Graph dumping.
std::string description() const
Return a simple one-line description of this object.
bool Setup(int coarseLevelID, const RCP< const FactoryManagerBase > fineLevelManager, const RCP< const FactoryManagerBase > coarseLevelManager, const RCP< const FactoryManagerBase > nextLevelManager=Teuchos::null)
Multi-level setup phase: build a new level of the hierarchy.
virtual std::string description() const
Return a simple one-line description of this object.
Array< RCP< const FactoryManagerBase > > levelManagers_
Xpetra::global_size_t maxCoarseSize_
void Request(const FactoryBase &factory)
Increment the storage counter for all the inputs of a factory.