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