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
18#include <Xpetra_Matrix.hpp>
19#include <Xpetra_MultiVectorFactory.hpp>
20#include <Xpetra_Operator.hpp>
21#include <Xpetra_IO.hpp>
22
24
25#include "MueLu_FactoryManager.hpp"
26#include "MueLu_HierarchyUtils.hpp"
27#include "MueLu_TopRAPFactory.hpp"
28#include "MueLu_TopSmootherFactory.hpp"
29#include "MueLu_Level.hpp"
30#include "MueLu_Monitor.hpp"
31#include "MueLu_PerfUtils.hpp"
32#include "MueLu_PFactory.hpp"
33#include "MueLu_SmootherFactory.hpp"
35
36#include "Teuchos_TimeMonitor.hpp"
37
38namespace MueLu {
39
40template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
42 : maxCoarseSize_(GetDefaultMaxCoarseSize())
43 , implicitTranspose_(GetDefaultImplicitTranspose())
44 , fuseProlongationAndUpdate_(GetDefaultFuseProlongationAndUpdate())
45 , doPRrebalance_(GetDefaultPRrebalance())
46 , doPRViaCopyrebalance_(false)
47 , isPreconditioner_(true)
48 , Cycle_(GetDefaultCycle())
49 , WCycleStartLevel_(0)
50 , scalingFactor_(Teuchos::ScalarTraits<double>::one())
51 , lib_(Xpetra::UseTpetra)
52 , isDumpingEnabled_(false)
53 , dumpLevel_(-2)
54 , rate_(-1)
55 , sizeOfAllocatedLevelMultiVectors_(0) {
56 AddLevel(rcp(new Level));
57}
58
59template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
61 : Hierarchy() {
62 SetLabel(label);
63 setObjectLabel(label);
64 Levels_[0]->setObjectLabel(label);
65}
66
67template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
69 : maxCoarseSize_(GetDefaultMaxCoarseSize())
70 , implicitTranspose_(GetDefaultImplicitTranspose())
71 , fuseProlongationAndUpdate_(GetDefaultFuseProlongationAndUpdate())
72 , doPRrebalance_(GetDefaultPRrebalance())
73 , doPRViaCopyrebalance_(false)
74 , isPreconditioner_(true)
75 , Cycle_(GetDefaultCycle())
76 , WCycleStartLevel_(0)
77 , scalingFactor_(Teuchos::ScalarTraits<double>::one())
78 , isDumpingEnabled_(false)
79 , dumpLevel_(-2)
80 , rate_(-1)
81 , sizeOfAllocatedLevelMultiVectors_(0) {
82 lib_ = A->getDomainMap()->lib();
83
84 RCP<Level> Finest = rcp(new Level);
85 AddLevel(Finest);
86
87 Finest->Set("A", A);
88}
89
90template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
91Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Hierarchy(const RCP<Matrix>& A, const std::string& label)
92 : Hierarchy(A) {
93 setObjectLabel(label);
94 Levels_[0]->setObjectLabel(label);
95}
96
97template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
99
100template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
102 int levelID = LastLevelID() + 1; // ID of the inserted level
103
104 if (level->GetLevelID() != -1 && (level->GetLevelID() != levelID))
105 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"
106 << " because last level ID of the hierarchy was " << LastLevelID() << "." << std::endl;
107
108 Levels_.push_back(level);
109 level->SetLevelID(levelID);
110 level->setlib(lib_);
111
112 level->SetPreviousLevel((levelID == 0) ? Teuchos::null : Levels_[LastLevelID() - 1]);
113 level->setObjectLabel(this->getObjectLabel());
114}
115
116template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
118 RCP<Level> newLevel = Levels_[LastLevelID()]->Build(); // new coarse level, using copy constructor
119 newLevel->setlib(lib_);
120 this->AddLevel(newLevel); // add to hierarchy
121}
122
123template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
125 TEUCHOS_TEST_FOR_EXCEPTION(levelID < 0 || levelID > LastLevelID(), Exceptions::RuntimeError,
126 "MueLu::Hierarchy::GetLevel(): invalid input parameter value: LevelID = " << levelID);
127 return Levels_[levelID];
128}
129
130template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
132 return Levels_.size();
133}
134
135template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
137 RCP<Operator> A = Levels_[0]->template Get<RCP<Operator>>("A");
138 RCP<const Teuchos::Comm<int>> comm = A->getDomainMap()->getComm();
139
140 int numLevels = GetNumLevels();
141 int numGlobalLevels;
142 Teuchos::reduceAll(*comm, Teuchos::REDUCE_MAX, numLevels, Teuchos::ptr(&numGlobalLevels));
143
144 return numGlobalLevels;
145}
146
147template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
149 double totalNnz = 0, lev0Nnz = 1;
150 for (int i = 0; i < GetNumLevels(); ++i) {
151 TEUCHOS_TEST_FOR_EXCEPTION(!(Levels_[i]->IsAvailable("A")), Exceptions::RuntimeError,
152 "Operator complexity cannot be calculated because A is unavailable on level " << i);
153 RCP<Operator> A = Levels_[i]->template Get<RCP<Operator>>("A");
154 if (A.is_null())
155 break;
156
157 RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
158 if (Am.is_null()) {
159 GetOStream(Warnings0) << "Some level operators are not matrices, operator complexity calculation aborted" << std::endl;
160 return 0.0;
161 }
162
163 totalNnz += as<double>(Am->getGlobalNumEntries());
164 if (i == 0)
165 lev0Nnz = totalNnz;
166 }
167 return totalNnz / lev0Nnz;
168}
169
170template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
172 double node_sc = 0, global_sc = 0;
173 double a0_nnz = 0;
174 const size_t INVALID = Teuchos::OrdinalTraits<size_t>::invalid();
175 // Get cost of fine matvec
176 if (GetNumLevels() <= 0) return -1.0;
177 if (!Levels_[0]->IsAvailable("A")) return -1.0;
178
179 RCP<Operator> A = Levels_[0]->template Get<RCP<Operator>>("A");
180 if (A.is_null()) return -1.0;
181 RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
182 if (Am.is_null()) return -1.0;
183 a0_nnz = as<double>(Am->getGlobalNumEntries());
184
185 // Get smoother complexity at each level
186 for (int i = 0; i < GetNumLevels(); ++i) {
187 size_t level_sc = 0;
188 if (!Levels_[i]->IsAvailable("PreSmoother")) continue;
189 RCP<SmootherBase> S = Levels_[i]->template Get<RCP<SmootherBase>>("PreSmoother");
190 if (S.is_null()) continue;
191 level_sc = S->getNodeSmootherComplexity();
192 if (level_sc == INVALID) {
193 global_sc = -1.0;
194 break;
195 }
196
197 node_sc += as<double>(level_sc);
198 }
199
200 double min_sc = 0.0;
201 RCP<const Teuchos::Comm<int>> comm = A->getDomainMap()->getComm();
202 Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, node_sc, Teuchos::ptr(&global_sc));
203 Teuchos::reduceAll(*comm, Teuchos::REDUCE_MIN, node_sc, Teuchos::ptr(&min_sc));
204
205 if (min_sc < 0.0)
206 return -1.0;
207 else
208 return global_sc / a0_nnz;
209}
210
211// Coherence checks todo in Setup() (using an helper function):
212template <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
222template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
224 for (int i = 0; i < GetNumLevels(); ++i) {
225 RCP<Level> level = Levels_[i];
226 if (level->IsAvailable("A")) {
227 RCP<Operator> Aop = level->Get<RCP<Operator>>("A");
228 RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Aop);
229 if (!A.is_null()) {
230 RCP<const Import> xpImporter = A->getCrsGraph()->getImporter();
231 if (!xpImporter.is_null())
232 xpImporter->setDistributorParameters(matvecParams);
233 RCP<const Export> xpExporter = A->getCrsGraph()->getExporter();
234 if (!xpExporter.is_null())
235 xpExporter->setDistributorParameters(matvecParams);
236 }
237 }
238 if (level->IsAvailable("P")) {
239 RCP<Matrix> P = level->Get<RCP<Matrix>>("P");
240 RCP<const Import> xpImporter = P->getCrsGraph()->getImporter();
241 if (!xpImporter.is_null())
242 xpImporter->setDistributorParameters(matvecParams);
243 RCP<const Export> xpExporter = P->getCrsGraph()->getExporter();
244 if (!xpExporter.is_null())
245 xpExporter->setDistributorParameters(matvecParams);
246 }
247 if (level->IsAvailable("R")) {
248 RCP<Matrix> R = level->Get<RCP<Matrix>>("R");
249 RCP<const Import> xpImporter = R->getCrsGraph()->getImporter();
250 if (!xpImporter.is_null())
251 xpImporter->setDistributorParameters(matvecParams);
252 RCP<const Export> xpExporter = R->getCrsGraph()->getExporter();
253 if (!xpExporter.is_null())
254 xpExporter->setDistributorParameters(matvecParams);
255 }
256 if (level->IsAvailable("Importer")) {
257 RCP<const Import> xpImporter = level->Get<RCP<const Import>>("Importer");
258 if (!xpImporter.is_null())
259 xpImporter->setDistributorParameters(matvecParams);
260 }
261 }
262}
263
264// The function uses three managers: fine, coarse and next coarse
265// We construct the data for the coarse level, and do requests for the next coarse
266template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
268 const RCP<const FactoryManagerBase> fineLevelManager,
269 const RCP<const FactoryManagerBase> coarseLevelManager,
270 const RCP<const FactoryManagerBase> nextLevelManager) {
271 // Use PrintMonitor/TimerMonitor instead of just a FactoryMonitor to print "Level 0" instead of Hierarchy(0)
272 // Print is done after the requests for next coarse level
273
274 TEUCHOS_TEST_FOR_EXCEPTION(LastLevelID() < coarseLevelID, Exceptions::RuntimeError,
275 "MueLu::Hierarchy:Setup(): level " << coarseLevelID << " (specified by coarseLevelID argument) "
276 "must be built before calling this function.");
277
278 Level& level = *Levels_[coarseLevelID];
279
280 bool useStackedTimer = !Teuchos::TimeMonitor::stackedTimerNameIsDefault();
281
282 std::string label = FormattingHelper::getColonLabel(level.getObjectLabel());
283 RCP<TimeMonitor> m1;
284 if (!useStackedTimer)
285 m1 = rcp(new TimeMonitor(*this, label + this->ShortClassName() + ": " + "Setup (total)"));
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)
342 DumpCurrentGraph(0);
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()
573 ResetDescription();
574
575 describe(GetOStream(Statistics0), GetVerbLevel());
576
577 CheckForEmptySmoothersAndCoarseSolve();
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
649 describe(GetOStream(Statistics0), GetVerbLevel());
650
651 CheckForEmptySmoothersAndCoarseSolve();
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 for (LO i = 1; i <= nIts; i++) {
780#ifdef HAVE_MUELU_DEBUG
781 if (A->getDomainMap()->isCompatible(*(X.getMap())) == false) {
782 std::ostringstream ss;
783 ss << "Level " << startLevel << ": level A's domain map is not compatible with X";
784 throw Exceptions::Incompatible(ss.str());
785 }
786
787 if (A->getRangeMap()->isCompatible(*(B.getMap())) == false) {
788 std::ostringstream ss;
789 ss << "Level " << startLevel << ": level A's range map is not compatible with B";
790 throw Exceptions::Incompatible(ss.str());
791 }
792#endif
793 }
794
795 bool emptyFineSolve = true;
796
797 RCP<MultiVector> fineX;
798 fineX = MultiVectorFactory::Build(X.getMap(), X.getNumVectors(), true);
799
800 // Synchronize_center->start();
801 // communicator->barrier();
802 // Synchronize_center->stop();
803
804 Concurrent->start();
805
806 // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
807 if (Fine->IsAvailable("PreSmoother")) {
808 RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
809 CompFine->start();
810 preSmoo->Apply(*fineX, B, zeroGuess);
811 CompFine->stop();
812 emptyFineSolve = false;
813 }
814 if (Fine->IsAvailable("PostSmoother")) {
815 RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
816 CompFine->start();
817 postSmoo->Apply(*fineX, B, zeroGuess);
818 CompFine->stop();
819
820 emptyFineSolve = false;
821 }
822 if (emptyFineSolve == true) {
823 // Fine grid smoother is identity
824 fineX->update(one, B, zero);
825 }
826
827 if (Levels_.size() > 1) {
828 // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
829 if (Coarse->IsAvailable("PreSmoother")) {
830 CompCoarse->start();
831 preSmoo_coarse->Apply(*coarseX, *coarseRhs, zeroGuess);
832 CompCoarse->stop();
833 emptyCoarseSolve = false;
834 }
835 if (Coarse->IsAvailable("PostSmoother")) {
836 CompCoarse->start();
837 postSmoo_coarse->Apply(*coarseX, *coarseRhs, zeroGuess);
838 CompCoarse->stop();
839 emptyCoarseSolve = false;
840 }
841 if (emptyCoarseSolve == true) {
842 // Coarse operator is identity
843 coarseX->update(one, *coarseRhs, zero);
844 }
845 Concurrent->stop();
846 // Synchronize_end->start();
847 // communicator->barrier();
848 // Synchronize_end->stop();
849
850 if (!doPRrebalance_ && !importer.is_null()) {
851 RCP<TimeMonitor> ITime = rcp(new TimeMonitor(*this, prefix + "Solve : export (total)", Timings0));
852 RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : export" + levelSuffix1, Timings0));
853
854 // Import: range map of rebalanced Ac (before subcomm replacement) --> domain map of P
855 RCP<MultiVector> coarseTmp = MultiVectorFactory::Build(importer->getSourceMap(), coarseX->getNumVectors());
856 coarseTmp->doExport(*coarseX, *importer, Xpetra::INSERT);
857 coarseX.swap(coarseTmp);
858 }
859
860 ApplyPbar->start();
861 Pbar->apply(*coarseX, *coarseX_prolonged, Teuchos::NO_TRANS, one, zero);
862 ApplyPbar->stop();
863 }
864
865 ApplySum->start();
866 X.update(1.0, *fineX, 1.0, *coarseX_prolonged, 0.0);
867 ApplySum->stop();
868
869 CompTime->stop();
870
871 // communicator->barrier();
872
874}
875#else
876// ---------------------------------------- Iterate -------------------------------------------------------
877template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
879 bool InitialGuessIsZero, LO startLevel) {
880 LO nIts = conv.maxIts_;
881 MagnitudeType tol = conv.tol_;
882
883 // These timers work as follows. "iterateTime" records total time spent in
884 // iterate. "levelTime" records time on a per level basis. The label is
885 // crafted to mimic the per-level messages used in Monitors. Note that a
886 // given level is timed with a TimeMonitor instead of a Monitor or
887 // SubMonitor. This is mainly because I want to time each level
888 // separately, and Monitors/SubMonitors print "(total) xx yy zz" ,
889 // "(sub,total) xx yy zz", respectively, which is subject to
890 // misinterpretation. The per-level TimeMonitors are stopped/started
891 // manually before/after a recursive call to Iterate. A side artifact to
892 // this approach is that the counts for intermediate level timers are twice
893 // the counts for the finest and coarsest levels.
894
895 RCP<Level> Fine = Levels_[startLevel];
896
897 std::string label = FormattingHelper::getColonLabel(Fine->getObjectLabel());
898 std::string prefix = label + this->ShortClassName() + ": ";
899 std::string levelSuffix = " (level=" + toString(startLevel) + ")";
900 std::string levelSuffix1 = " (level=" + toString(startLevel + 1) + ")";
901
902 bool useStackedTimer = !Teuchos::TimeMonitor::stackedTimerNameIsDefault();
903
904 RCP<Monitor> iterateTime;
905 RCP<TimeMonitor> iterateTime1;
906 if (startLevel == 0)
907 iterateTime = rcp(new Monitor(*this, "Solve", label, (nIts == 1) ? None : Runtime0, Timings0));
908 else if (!useStackedTimer)
909 iterateTime1 = rcp(new TimeMonitor(*this, prefix + "Solve (total, level=" + toString(startLevel) + ")", Timings0));
910
911 std::string iterateLevelTimeLabel = prefix + "Solve" + levelSuffix;
912 RCP<TimeMonitor> iterateLevelTime = rcp(new TimeMonitor(*this, iterateLevelTimeLabel, Timings0));
913
914 bool zeroGuess = InitialGuessIsZero;
915
916 RCP<Operator> A = Fine->Get<RCP<Operator>>("A");
917 using namespace Teuchos;
918 RCP<Time> CompCoarse = Teuchos::TimeMonitor::getNewCounter(prefix + "Coarse: Computational Time");
919
920 if (A.is_null()) {
921 // This processor does not have any data for this process on coarser
922 // levels. This can only happen when there are multiple processors and
923 // we use repartitioning.
925 }
926
927 // If we switched the number of vectors, we'd need to reallocate here.
928 // If the number of vectors is unchanged, this is a noop.
929 // NOTE: We need to check against B because the tests in AllocateLevelMultiVectors
930 // will fail on Stokhos Scalar types (due to the so-called 'hidden dimension')
931 const BlockedMultiVector* Bblocked = dynamic_cast<const BlockedMultiVector*>(&B);
932 if (residual_.size() > startLevel &&
933 ((Bblocked && !Bblocked->isSameSize(*residual_[startLevel])) ||
934 (!Bblocked && !residual_[startLevel]->isSameSize(B))))
935 DeleteLevelMultiVectors();
936 AllocateLevelMultiVectors(X.getNumVectors());
937
938 // Print residual information before iterating
939 typedef Teuchos::ScalarTraits<typename STS::magnitudeType> STM;
940 MagnitudeType prevNorm = STM::one();
941 rate_ = 1.0;
942 if (IsCalculationOfResidualRequired(startLevel, conv)) {
943 ConvergenceStatus convergenceStatus = ComputeResidualAndPrintHistory(*A, X, B, Teuchos::ScalarTraits<LO>::zero(), startLevel, conv, prevNorm);
944 if (convergenceStatus == MueLu::ConvergenceStatus::Converged)
945 return convergenceStatus;
946 }
947
948 SC one = STS::one(), zero = STS::zero();
949 for (LO iteration = 1; iteration <= nIts; iteration++) {
950#ifdef HAVE_MUELU_DEBUG
951#if 0 // TODO fix me
952 if (A->getDomainMap()->isCompatible(*(X.getMap())) == false) {
953 std::ostringstream ss;
954 ss << "Level " << startLevel << ": level A's domain map is not compatible with X";
955 throw Exceptions::Incompatible(ss.str());
956 }
957
958 if (A->getRangeMap()->isCompatible(*(B.getMap())) == false) {
959 std::ostringstream ss;
960 ss << "Level " << startLevel << ": level A's range map is not compatible with B";
961 throw Exceptions::Incompatible(ss.str());
962 }
963#endif
964#endif
965
966 if (startLevel == as<LO>(Levels_.size()) - 1) {
967 // On the coarsest level, we do either smoothing (if defined) or a direct solve.
968 RCP<TimeMonitor> CLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : coarse" + levelSuffix, Timings0));
969
970 bool emptySolve = true;
971
972 // NOTE: we need to check using IsAvailable before Get here to avoid building default smoother
973 if (Fine->IsAvailable("PreSmoother")) {
974 RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
975 CompCoarse->start();
976 preSmoo->Apply(X, B, zeroGuess);
977 CompCoarse->stop();
978 zeroGuess = false;
979 emptySolve = false;
980 }
981 if (Fine->IsAvailable("PostSmoother")) {
982 RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
983 CompCoarse->start();
984 postSmoo->Apply(X, B, zeroGuess);
985 CompCoarse->stop();
986 emptySolve = false;
987 zeroGuess = false;
988 }
989 if (emptySolve == true) {
990 // Coarse operator is identity
991 X.update(one, B, zero);
992 }
993
994 } else {
995 // On intermediate levels, we do cycles
996 RCP<Level> Coarse = Levels_[startLevel + 1];
997 {
998 // ============== PRESMOOTHING ==============
999 RCP<TimeMonitor> STime;
1000 if (!useStackedTimer)
1001 STime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing (total)", Timings0));
1002 RCP<TimeMonitor> SLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing" + levelSuffix, Timings0));
1003
1004 if (Fine->IsAvailable("PreSmoother")) {
1005 RCP<SmootherBase> preSmoo = Fine->Get<RCP<SmootherBase>>("PreSmoother");
1006 preSmoo->Apply(X, B, zeroGuess);
1007 zeroGuess = false;
1008 }
1009 }
1010
1011 RCP<MultiVector> residual;
1012 {
1013 RCP<TimeMonitor> ATime;
1014 if (!useStackedTimer)
1015 ATime = rcp(new TimeMonitor(*this, prefix + "Solve : residual calculation (total)", Timings0));
1016 RCP<TimeMonitor> ALevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : residual calculation" + levelSuffix, Timings0));
1017 if (zeroGuess) {
1018 // If there's a pre-smoother, then zeroGuess is false. If there isn't and people still have zeroGuess set,
1019 // then then X still has who knows what, so we need to zero it before we go to the coarse grid.
1020 X.putScalar(zero);
1021 }
1022
1023 Utilities::Residual(*A, X, B, *residual_[startLevel]);
1024 residual = residual_[startLevel];
1025 }
1026
1027 RCP<Operator> P = Coarse->Get<RCP<Operator>>("P");
1028 if (Coarse->IsAvailable("Pbar"))
1029 P = Coarse->Get<RCP<Operator>>("Pbar");
1030
1031 RCP<MultiVector> coarseRhs, coarseX;
1032 // const bool initializeWithZeros = true;
1033 {
1034 // ============== RESTRICTION ==============
1035 RCP<TimeMonitor> RTime;
1036 if (!useStackedTimer)
1037 RTime = rcp(new TimeMonitor(*this, prefix + "Solve : restriction (total)", Timings0));
1038 RCP<TimeMonitor> RLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : restriction" + levelSuffix, Timings0));
1039 coarseRhs = coarseRhs_[startLevel];
1040
1041 if (implicitTranspose_) {
1042 P->apply(*residual, *coarseRhs, Teuchos::TRANS, one, zero);
1043
1044 } else {
1045 RCP<Operator> R = Coarse->Get<RCP<Operator>>("R");
1046 R->apply(*residual, *coarseRhs, Teuchos::NO_TRANS, one, zero);
1047 }
1048 }
1049
1050 RCP<const Import> importer;
1051 if (Coarse->IsAvailable("Importer"))
1052 importer = Coarse->Get<RCP<const Import>>("Importer");
1053
1054 coarseX = coarseX_[startLevel];
1055 if (!doPRrebalance_ && !importer.is_null()) {
1056 RCP<TimeMonitor> ITime;
1057 if (!useStackedTimer)
1058 ITime = rcp(new TimeMonitor(*this, prefix + "Solve : import (total)", Timings0));
1059 RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : import" + levelSuffix1, Timings0));
1060
1061 // Import: range map of R --> domain map of rebalanced Ac (before subcomm replacement)
1062 RCP<MultiVector> coarseTmp = coarseImport_[startLevel];
1063 coarseTmp->doImport(*coarseRhs, *importer, Xpetra::INSERT);
1064 coarseRhs.swap(coarseTmp);
1065 }
1066
1067 RCP<Operator> Ac = Coarse->Get<RCP<Operator>>("A");
1068 if (!Ac.is_null()) {
1069 RCP<const Map> origXMap = coarseX->getMap();
1070 RCP<const Map> origRhsMap = coarseRhs->getMap();
1071
1072 // Replace maps with maps with a subcommunicator
1073 coarseRhs->replaceMap(Ac->getRangeMap());
1074 coarseX->replaceMap(Ac->getDomainMap());
1075
1076 {
1077 iterateLevelTime = Teuchos::null; // stop timing this level
1078
1079 Iterate(*coarseRhs, *coarseX, 1, true, startLevel + 1);
1080 // ^^ zero initial guess
1081 if (Cycle_ == WCYCLE && WCycleStartLevel_ <= startLevel)
1082 Iterate(*coarseRhs, *coarseX, 1, false, startLevel + 1);
1083 // ^^ nonzero initial guess
1084
1085 iterateLevelTime = rcp(new TimeMonitor(*this, iterateLevelTimeLabel)); // restart timing this level
1086 }
1087 coarseX->replaceMap(origXMap);
1088 coarseRhs->replaceMap(origRhsMap);
1089 }
1090
1091 if (!doPRrebalance_ && !importer.is_null()) {
1092 RCP<TimeMonitor> ITime;
1093 if (!useStackedTimer)
1094 ITime = rcp(new TimeMonitor(*this, prefix + "Solve : export (total)", Timings0));
1095 RCP<TimeMonitor> ILevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : export" + levelSuffix1, Timings0));
1096
1097 // Import: range map of rebalanced Ac (before subcomm replacement) --> domain map of P
1098 RCP<MultiVector> coarseTmp = coarseExport_[startLevel];
1099 coarseTmp->doExport(*coarseX, *importer, Xpetra::INSERT);
1100 coarseX.swap(coarseTmp);
1101 }
1102
1103 {
1104 // ============== PROLONGATION ==============
1105 RCP<TimeMonitor> PTime;
1106 if (!useStackedTimer)
1107 PTime = rcp(new TimeMonitor(*this, prefix + "Solve : prolongation (total)", Timings0));
1108 RCP<TimeMonitor> PLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : prolongation" + levelSuffix, Timings0));
1109 // Update X += P * coarseX
1110 // Note that due to what may be round-off error accumulation, use of the fused kernel
1111 // P->apply(*coarseX, X, Teuchos::NO_TRANS, one, one);
1112 // can in some cases result in slightly higher iteration counts.
1113 if (fuseProlongationAndUpdate_) {
1114 P->apply(*coarseX, X, Teuchos::NO_TRANS, scalingFactor_, one);
1115 } else {
1116 RCP<MultiVector> correction = correction_[startLevel];
1117 P->apply(*coarseX, *correction, Teuchos::NO_TRANS, one, zero);
1118 X.update(scalingFactor_, *correction, one);
1119 }
1120 }
1121
1122 {
1123 // ============== POSTSMOOTHING ==============
1124 RCP<TimeMonitor> STime;
1125 if (!useStackedTimer)
1126 STime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing (total)", Timings0));
1127 RCP<TimeMonitor> SLevelTime = rcp(new TimeMonitor(*this, prefix + "Solve : smoothing" + levelSuffix, Timings0));
1128
1129 if (Fine->IsAvailable("PostSmoother")) {
1130 RCP<SmootherBase> postSmoo = Fine->Get<RCP<SmootherBase>>("PostSmoother");
1131 postSmoo->Apply(X, B, false);
1132 }
1133 }
1134 }
1135 zeroGuess = false;
1136
1137 if (IsCalculationOfResidualRequired(startLevel, conv)) {
1138 ConvergenceStatus convergenceStatus = ComputeResidualAndPrintHistory(*A, X, B, iteration, startLevel, conv, prevNorm);
1139 if (convergenceStatus == MueLu::ConvergenceStatus::Converged)
1140 return convergenceStatus;
1141 }
1142 }
1144}
1145#endif
1146
1147template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1148void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(const LO& start, const LO& end, const std::string& suffix) {
1149 LO startLevel = (start != -1 ? start : 0);
1150 LO endLevel = (end != -1 ? end : Levels_.size() - 1);
1151
1152 TEUCHOS_TEST_FOR_EXCEPTION(startLevel > endLevel, Exceptions::RuntimeError,
1153 "MueLu::Hierarchy::Write : startLevel must be <= endLevel");
1154
1155 TEUCHOS_TEST_FOR_EXCEPTION(startLevel < 0 || endLevel >= Levels_.size(), Exceptions::RuntimeError,
1156 "MueLu::Hierarchy::Write bad start or end level");
1157
1158 for (LO i = startLevel; i < endLevel + 1; i++) {
1159 RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Levels_[i]->template Get<RCP<Operator>>("A")), P, R;
1160 if (i > 0) {
1161 P = rcp_dynamic_cast<Matrix>(Levels_[i]->template Get<RCP<Operator>>("P"));
1162 if (!implicitTranspose_)
1163 R = rcp_dynamic_cast<Matrix>(Levels_[i]->template Get<RCP<Operator>>("R"));
1164 }
1165
1166 if (!A.is_null()) Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("A_" + toString(i) + suffix + ".m", *A);
1167 if (!P.is_null()) {
1168 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("P_" + toString(i) + suffix + ".m", *P);
1169 }
1170 if (!R.is_null()) {
1171 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write("R_" + toString(i) + suffix + ".m", *R);
1172 }
1173 }
1174}
1175
1176template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1177void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Keep(const std::string& ename, const FactoryBase* factory) {
1178 for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1179 (*it)->Keep(ename, factory);
1180}
1181
1182template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1184 for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1185 (*it)->Delete(ename, factory);
1186}
1187
1188template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1190 for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1191 (*it)->AddKeepFlag(ename, factory, keep);
1192}
1193
1194template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1196 for (Array<RCP<Level>>::iterator it = Levels_.begin(); it != Levels_.end(); ++it)
1197 (*it)->RemoveKeepFlag(ename, factory, keep);
1198}
1199
1200template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1202 if (description_.empty()) {
1203 std::ostringstream out;
1204 out << BaseClass::description();
1205 out << "{#levels = " << GetGlobalNumLevels() << ", complexity = " << GetOperatorComplexity() << "}";
1206 description_ = out.str();
1207 }
1208 return description_;
1209}
1210
1211template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1212void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::describe(Teuchos::FancyOStream& out, const Teuchos::EVerbosityLevel tVerbLevel) const {
1213 describe(out, toMueLuVerbLevel(tVerbLevel));
1214}
1215
1216template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1217void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::describe(Teuchos::FancyOStream& out, const VerbLevel verbLevel) const {
1218 RCP<Operator> A0 = Levels_[0]->template Get<RCP<Operator>>("A");
1219 RCP<const Teuchos::Comm<int>> comm = A0->getDomainMap()->getComm();
1220
1221 int numLevels = GetNumLevels();
1222 RCP<Operator> Ac = Levels_[numLevels - 1]->template Get<RCP<Operator>>("A");
1223 if (Ac.is_null()) {
1224 // It may happen that we do repartition on the last level, but the matrix
1225 // is small enough to satisfy "max coarse size" requirement. Then, even
1226 // though we have the level, the matrix would be null on all but one processors
1227 numLevels--;
1228 }
1229 int root = comm->getRank();
1230
1231#ifdef HAVE_MPI
1232 int smartData = numLevels * comm->getSize() + comm->getRank(), maxSmartData;
1233 reduceAll(*comm, Teuchos::REDUCE_MAX, smartData, Teuchos::ptr(&maxSmartData));
1234 root = maxSmartData % comm->getSize();
1235#endif
1236
1237 // Compute smoother complexity, if needed
1238 double smoother_comp = -1.0;
1239 if (verbLevel & (Statistics0 | Test))
1240 smoother_comp = GetSmootherComplexity();
1241
1242 std::string outstr;
1243 if (comm->getRank() == root && verbLevel & (Statistics0 | Test)) {
1244 std::vector<Xpetra::global_size_t> nnzPerLevel;
1245 std::vector<Xpetra::global_size_t> rowsPerLevel;
1246 std::vector<int> numProcsPerLevel;
1247 bool someOpsNotMatrices = false;
1248 const Xpetra::global_size_t INVALID = Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid();
1249 for (int i = 0; i < numLevels; i++) {
1250 TEUCHOS_TEST_FOR_EXCEPTION(!(Levels_[i]->IsAvailable("A")), Exceptions::RuntimeError,
1251 "Operator A is not available on level " << i);
1252
1253 RCP<Operator> A = Levels_[i]->template Get<RCP<Operator>>("A");
1254 TEUCHOS_TEST_FOR_EXCEPTION(A.is_null(), Exceptions::RuntimeError,
1255 "Operator A on level " << i << " is null.");
1256
1257 RCP<Matrix> Am = rcp_dynamic_cast<Matrix>(A);
1258 if (Am.is_null()) {
1259 someOpsNotMatrices = true;
1260 nnzPerLevel.push_back(INVALID);
1261 rowsPerLevel.push_back(A->getDomainMap()->getGlobalNumElements());
1262 numProcsPerLevel.push_back(A->getDomainMap()->getComm()->getSize());
1263 } else {
1264 LO storageblocksize = Am->GetStorageBlockSize();
1265 Xpetra::global_size_t nnz = Am->getGlobalNumEntries() * storageblocksize * storageblocksize;
1266 nnzPerLevel.push_back(nnz);
1267 rowsPerLevel.push_back(Am->getGlobalNumRows() * storageblocksize);
1268 numProcsPerLevel.push_back(Am->getRowMap()->getComm()->getSize());
1269 }
1270 }
1271 if (someOpsNotMatrices)
1272 GetOStream(Warnings0) << "Some level operators are not matrices, statistics calculation are incomplete" << std::endl;
1273
1274 {
1275 std::string label = Levels_[0]->getObjectLabel();
1276 std::ostringstream oss;
1277 oss << std::setfill(' ');
1278 oss << "\n--------------------------------------------------------------------------------\n";
1279 oss << "--- Multigrid Summary " << std::setw(32) << "---\n";
1280 oss << "--------------------------------------------------------------------------------" << std::endl;
1281 if (hierarchyLabel_ != "") oss << "Label = " << hierarchyLabel_ << std::endl;
1282 if (verbLevel & Parameters1)
1283 oss << "Scalar = " << Teuchos::ScalarTraits<Scalar>::name() << std::endl;
1284 oss << "Number of levels = " << numLevels << std::endl;
1285 oss << "Operator complexity = " << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1286 if (!someOpsNotMatrices)
1287 oss << GetOperatorComplexity() << std::endl;
1288 else
1289 oss << "not available (Some operators in hierarchy are not matrices.)" << std::endl;
1290
1291 if (smoother_comp != -1.0) {
1292 oss << "Smoother complexity = " << std::setprecision(2) << std::setiosflags(std::ios::fixed)
1293 << smoother_comp << std::endl;
1294 }
1295
1296 switch (Cycle_) {
1297 case VCYCLE:
1298 oss << "Cycle type = V" << std::endl;
1299 break;
1300 case WCYCLE:
1301 oss << "Cycle type = W" << std::endl;
1302 if (WCycleStartLevel_ > 0)
1303 oss << "Cycle start level = " << WCycleStartLevel_ << std::endl;
1304 break;
1305 default:
1306 break;
1307 };
1308 oss << std::endl;
1309
1310 Xpetra::global_size_t tt = rowsPerLevel[0];
1311 int rowspacer = 2;
1312 while (tt != 0) {
1313 tt /= 10;
1314 rowspacer++;
1315 }
1316 for (size_t i = 0; i < nnzPerLevel.size(); ++i) {
1317 tt = nnzPerLevel[i];
1318 if (tt != INVALID)
1319 break;
1320 tt = 100; // This will get used if all levels are operators.
1321 }
1322 int nnzspacer = 2;
1323 while (tt != 0) {
1324 tt /= 10;
1325 nnzspacer++;
1326 }
1327 tt = numProcsPerLevel[0];
1328 int npspacer = 2;
1329 while (tt != 0) {
1330 tt /= 10;
1331 npspacer++;
1332 }
1333 oss << "level " << std::setw(rowspacer) << " rows " << std::setw(nnzspacer) << " nnz "
1334 << " nnz/row" << std::setw(npspacer) << " c ratio"
1335 << " procs" << std::endl;
1336 for (size_t i = 0; i < nnzPerLevel.size(); ++i) {
1337 oss << " " << i << " ";
1338 oss << std::setw(rowspacer) << rowsPerLevel[i];
1339 if (nnzPerLevel[i] != INVALID) {
1340 oss << std::setw(nnzspacer) << nnzPerLevel[i];
1341 oss << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1342 oss << std::setw(9) << as<double>(nnzPerLevel[i]) / rowsPerLevel[i];
1343 } else {
1344 oss << std::setw(nnzspacer) << "Operator";
1345 oss << std::setprecision(2) << std::setiosflags(std::ios::fixed);
1346 oss << std::setw(9) << " ";
1347 }
1348 if (i)
1349 oss << std::setw(9) << as<double>(rowsPerLevel[i - 1]) / rowsPerLevel[i];
1350 else
1351 oss << std::setw(9) << " ";
1352 oss << " " << std::setw(npspacer) << numProcsPerLevel[i] << std::endl;
1353 }
1354 oss << std::endl;
1355 for (int i = 0; i < GetNumLevels(); ++i) {
1356 RCP<SmootherBase> preSmoo, postSmoo;
1357 if (Levels_[i]->IsAvailable("PreSmoother"))
1358 preSmoo = Levels_[i]->template Get<RCP<SmootherBase>>("PreSmoother");
1359 if (Levels_[i]->IsAvailable("PostSmoother"))
1360 postSmoo = Levels_[i]->template Get<RCP<SmootherBase>>("PostSmoother");
1361
1362 if (preSmoo != null && preSmoo == postSmoo)
1363 oss << "Smoother (level " << i << ") both : " << preSmoo->description() << std::endl;
1364 else {
1365 oss << "Smoother (level " << i << ") pre : "
1366 << (preSmoo != null ? preSmoo->description() : "no smoother") << std::endl;
1367 oss << "Smoother (level " << i << ") post : "
1368 << (postSmoo != null ? postSmoo->description() : "no smoother") << std::endl;
1369 }
1370
1371 oss << std::endl;
1372 }
1373
1374 outstr = oss.str();
1375 }
1376 }
1377
1378#ifdef HAVE_MPI
1379 RCP<const Teuchos::MpiComm<int>> mpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int>>(comm);
1380 MPI_Comm rawComm = (*mpiComm->getRawMpiComm())();
1381
1382 int strLength = outstr.size();
1383 MPI_Bcast(&strLength, 1, MPI_INT, root, rawComm);
1384 if (comm->getRank() != root)
1385 outstr.resize(strLength);
1386 MPI_Bcast(&outstr[0], strLength, MPI_CHAR, root, rawComm);
1387#endif
1388
1389 out << outstr;
1390}
1391
1392// NOTE: at some point this should be replaced by a friend operator <<
1393template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1394void Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>::print(std::ostream& out, const VerbLevel verbLevel) const {
1395 Teuchos::OSTab tab2(out);
1396 for (int i = 0; i < GetNumLevels(); ++i)
1397 Levels_[i]->print(out, verbLevel);
1398}
1399
1400template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1402 isPreconditioner_ = flag;
1403}
1404
1405template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1407 if (GetProcRankVerbose() != 0)
1408 return;
1409#if defined(HAVE_MUELU_BOOST) && defined(HAVE_MUELU_BOOST_FOR_REAL) && defined(BOOST_VERSION) && (BOOST_VERSION >= 104400)
1410
1411 BoostGraph graph;
1412
1413 BoostProperties dp;
1414 dp.property("label", boost::get(boost::vertex_name, graph));
1415 dp.property("id", boost::get(boost::vertex_index, graph));
1416 dp.property("label", boost::get(boost::edge_name, graph));
1417 dp.property("color", boost::get(boost::edge_color, graph));
1418
1419 // create local maps
1420 std::map<const FactoryBase*, BoostVertex> vindices;
1421 typedef std::map<std::pair<BoostVertex, BoostVertex>, std::string> emap;
1422 emap edges;
1423
1424 static int call_id = 0;
1425
1426 RCP<Operator> A = Levels_[0]->template Get<RCP<Operator>>("A");
1427 int rank = A->getDomainMap()->getComm()->getRank();
1428
1429 // printf("[%d] CMS: ----------------------\n",rank);
1430 for (int i = currLevel; i <= currLevel + 1 && i < GetNumLevels(); i++) {
1431 edges.clear();
1432 Levels_[i]->UpdateGraph(vindices, edges, dp, graph);
1433
1434 for (emap::const_iterator eit = edges.begin(); eit != edges.end(); eit++) {
1435 std::pair<BoostEdge, bool> boost_edge = boost::add_edge(eit->first.first, eit->first.second, graph);
1436 // printf("[%d] CMS: Hierarchy, adding edge (%d->%d) %d\n",rank,(int)eit->first.first,(int)eit->first.second,(int)boost_edge.second);
1437 // Because xdot.py views 'Graph' as a keyword
1438 if (eit->second == std::string("Graph"))
1439 boost::put("label", dp, boost_edge.first, std::string("Graph_"));
1440 else
1441 boost::put("label", dp, boost_edge.first, eit->second);
1442 if (i == currLevel)
1443 boost::put("color", dp, boost_edge.first, std::string("red"));
1444 else
1445 boost::put("color", dp, boost_edge.first, std::string("blue"));
1446 }
1447 }
1448
1449 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"));
1450 boost::write_graphviz_dp(out, graph, dp, std::string("id"));
1451 out.close();
1452 call_id++;
1453#else
1454 GetOStream(Errors) << "Dependency graph output requires boost and MueLu_ENABLE_Boost_for_real" << std::endl;
1455#endif
1456}
1457
1458// Enforce that coordinate vector's map is consistent with that of A
1459template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1461 RCP<Operator> Ao = level.Get<RCP<Operator>>("A");
1462 RCP<Matrix> A = rcp_dynamic_cast<Matrix>(Ao);
1463 if (A.is_null()) {
1464 GetOStream(Runtime1) << "Hierarchy::ReplaceCoordinateMap: operator is not a matrix, skipping..." << std::endl;
1465 return;
1466 }
1467 if (Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(A) != Teuchos::null) {
1468 GetOStream(Runtime1) << "Hierarchy::ReplaceCoordinateMap: operator is a BlockedCrsMatrix, skipping..." << std::endl;
1469 return;
1470 }
1471
1472 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::coordinateType, LO, GO, NO> xdMV;
1473
1474 RCP<xdMV> coords = level.Get<RCP<xdMV>>("Coordinates");
1475
1476 if (A->getRowMap()->isSameAs(*(coords->getMap()))) {
1477 GetOStream(Runtime1) << "Hierarchy::ReplaceCoordinateMap: matrix and coordinates maps are same, skipping..." << std::endl;
1478 return;
1479 }
1480
1481 if (A->IsView("stridedMaps") && rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps")) != Teuchos::null) {
1482 RCP<const StridedMap> stridedRowMap = rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps"));
1483
1484 // It is better to through an exceptions if maps may be inconsistent, than to ignore it and experience unfathomable breakdowns
1485 TEUCHOS_TEST_FOR_EXCEPTION(stridedRowMap->getStridedBlockId() != -1 || stridedRowMap->getOffset() != 0,
1486 Exceptions::RuntimeError, "Hierarchy::ReplaceCoordinateMap: nontrivial maps (block id = " << stridedRowMap->getStridedBlockId() << ", offset = " << stridedRowMap->getOffset() << ")");
1487 }
1488
1489 GetOStream(Runtime1) << "Replacing coordinate map" << std::endl;
1490 TEUCHOS_TEST_FOR_EXCEPTION(A->GetFixedBlockSize() % A->GetStorageBlockSize() != 0, Exceptions::RuntimeError, "Hierarchy::ReplaceCoordinateMap: Storage block size does not evenly divide fixed block size");
1491
1492 size_t blkSize = A->GetFixedBlockSize() / A->GetStorageBlockSize();
1493
1494 RCP<const Map> nodeMap = A->getRowMap();
1495 if (blkSize > 1) {
1496 // Create a nodal map, as coordinates have not been expanded to a DOF map yet.
1497 RCP<const Map> dofMap = A->getRowMap();
1498 GO indexBase = dofMap->getIndexBase();
1499 size_t numLocalDOFs = dofMap->getLocalNumElements();
1500 TEUCHOS_TEST_FOR_EXCEPTION(numLocalDOFs % blkSize, Exceptions::RuntimeError,
1501 "Hierarchy::ReplaceCoordinateMap: block size (" << blkSize << ") is incompatible with the number of local dofs in a row map (" << numLocalDOFs);
1502 ArrayView<const GO> GIDs = dofMap->getLocalElementList();
1503
1504 Array<GO> nodeGIDs(numLocalDOFs / blkSize);
1505 for (size_t i = 0; i < numLocalDOFs; i += blkSize)
1506 nodeGIDs[i / blkSize] = (GIDs[i] - indexBase) / blkSize + indexBase;
1507
1508 Xpetra::global_size_t INVALID = Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid();
1509 nodeMap = MapFactory::Build(dofMap->lib(), INVALID, nodeGIDs(), indexBase, dofMap->getComm());
1510 } else {
1511 // blkSize == 1
1512 // Check whether the length of vectors fits to the size of A
1513 // If yes, make sure that the maps are matching
1514 // If no, throw a warning but do not touch the Coordinates
1515 if (coords->getLocalLength() != A->getRowMap()->getLocalNumElements()) {
1516 GetOStream(Warnings) << "Coordinate vector does not match row map of matrix A!" << std::endl;
1517 return;
1518 }
1519 }
1520
1521 Array<ArrayView<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>> coordDataView;
1522 std::vector<ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>> coordData;
1523 for (size_t i = 0; i < coords->getNumVectors(); i++) {
1524 coordData.push_back(coords->getData(i));
1525 coordDataView.push_back(coordData[i]());
1526 }
1527
1528 RCP<xdMV> newCoords = Xpetra::MultiVectorFactory<typename Teuchos::ScalarTraits<Scalar>::coordinateType, LO, GO, NO>::Build(nodeMap, coordDataView(), coords->getNumVectors());
1529 level.Set("Coordinates", newCoords);
1530}
1531
1532template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1534 int N = Levels_.size();
1535 if (((sizeOfAllocatedLevelMultiVectors_ == numvecs && residual_.size() == N) || numvecs <= 0) && !forceMapCheck) return;
1536
1537 // If, somehow, we changed the number of levels, delete everything first
1538 if (residual_.size() != N) {
1539 DeleteLevelMultiVectors();
1540
1541 residual_.resize(N);
1542 coarseRhs_.resize(N);
1543 coarseX_.resize(N);
1544 coarseImport_.resize(N);
1545 coarseExport_.resize(N);
1546 correction_.resize(N);
1547 }
1548
1549 for (int i = 0; i < N; i++) {
1550 RCP<Operator> A = Levels_[i]->template Get<RCP<Operator>>("A");
1551 if (!A.is_null()) {
1552 // This dance is because we allow A to have a BlockedMap and X/B to have (compatible) non-blocked map
1553 RCP<const BlockedCrsMatrix> A_as_blocked = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(A);
1554 RCP<const Map> Arm = A->getRangeMap();
1555 RCP<const Map> Adm = A->getDomainMap();
1556 if (!A_as_blocked.is_null()) {
1557 Adm = A_as_blocked->getFullDomainMap();
1558 }
1559
1560 if (residual_[i].is_null() || !residual_[i]->getMap()->isSameAs(*Arm))
1561 // This is zero'd by default since it is filled via an operator apply
1562 residual_[i] = MultiVectorFactory::Build(Arm, numvecs, true);
1563 if (correction_[i].is_null() || !correction_[i]->getMap()->isSameAs(*Adm))
1564 correction_[i] = MultiVectorFactory::Build(Adm, numvecs, false);
1565 }
1566
1567 if (i + 1 < N) {
1568 // This is zero'd by default since it is filled via an operator apply
1569 if (implicitTranspose_) {
1570 RCP<Operator> P = Levels_[i + 1]->template Get<RCP<Operator>>("P");
1571 if (!P.is_null()) {
1572 RCP<const Map> map = P->getDomainMap();
1573 if (coarseRhs_[i].is_null() || !coarseRhs_[i]->getMap()->isSameAs(*map))
1574 coarseRhs_[i] = MultiVectorFactory::Build(map, numvecs, true);
1575 }
1576 } else {
1577 RCP<Operator> R = Levels_[i + 1]->template Get<RCP<Operator>>("R");
1578 if (!R.is_null()) {
1579 RCP<const Map> map = R->getRangeMap();
1580 if (coarseRhs_[i].is_null() || !coarseRhs_[i]->getMap()->isSameAs(*map))
1581 coarseRhs_[i] = MultiVectorFactory::Build(map, numvecs, true);
1582 }
1583 }
1584
1585 RCP<const Import> importer;
1586 if (Levels_[i + 1]->IsAvailable("Importer"))
1587 importer = Levels_[i + 1]->template Get<RCP<const Import>>("Importer");
1588 if (doPRrebalance_ || importer.is_null()) {
1589 RCP<const Map> map = coarseRhs_[i]->getMap();
1590 if (coarseX_[i].is_null() || !coarseX_[i]->getMap()->isSameAs(*map))
1591 coarseX_[i] = MultiVectorFactory::Build(map, numvecs, true);
1592 } else {
1593 RCP<const Map> map;
1594 map = importer->getTargetMap();
1595 if (coarseImport_[i].is_null() || !coarseImport_[i]->getMap()->isSameAs(*map)) {
1596 coarseImport_[i] = MultiVectorFactory::Build(map, numvecs, false);
1597 coarseX_[i] = MultiVectorFactory::Build(map, numvecs, false);
1598 }
1599 map = importer->getSourceMap();
1600 if (coarseExport_[i].is_null() || !coarseExport_[i]->getMap()->isSameAs(*map))
1601 coarseExport_[i] = MultiVectorFactory::Build(map, numvecs, false);
1602 }
1603 }
1604 }
1605 sizeOfAllocatedLevelMultiVectors_ = numvecs;
1606}
1607
1608template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1610 if (sizeOfAllocatedLevelMultiVectors_ == 0) return;
1611 residual_.resize(0);
1612 coarseRhs_.resize(0);
1613 coarseX_.resize(0);
1614 coarseImport_.resize(0);
1615 coarseExport_.resize(0);
1616 correction_.resize(0);
1617 sizeOfAllocatedLevelMultiVectors_ = 0;
1618}
1619
1620template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1622 const LO startLevel, const ConvData& conv) const {
1623 return (startLevel == 0 && !isPreconditioner_ && (IsPrint(Statistics1) || conv.tol_ > 0));
1624}
1625
1626template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1628 const Teuchos::Array<MagnitudeType>& residualNorm, const MagnitudeType convergenceTolerance) const {
1630
1631 if (convergenceTolerance > Teuchos::ScalarTraits<MagnitudeType>::zero()) {
1632 bool passed = true;
1633 for (LO k = 0; k < residualNorm.size(); k++)
1634 if (residualNorm[k] >= convergenceTolerance)
1635 passed = false;
1636
1637 if (passed)
1638 convergenceStatus = ConvergenceStatus::Converged;
1639 else
1640 convergenceStatus = ConvergenceStatus::Unconverged;
1641 }
1642
1643 return convergenceStatus;
1644}
1645
1646template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1648 const LO iteration, const Teuchos::Array<MagnitudeType>& residualNorm) const {
1649 GetOStream(Statistics1) << "iter: "
1650 << std::setiosflags(std::ios::left)
1651 << std::setprecision(3) << std::setw(4) << iteration
1652 << " residual = "
1653 << std::setprecision(10) << residualNorm
1654 << std::endl;
1655}
1656
1657template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1659 const Operator& A, const MultiVector& X, const MultiVector& B, const LO iteration,
1660 const LO startLevel, const ConvData& conv, MagnitudeType& previousResidualNorm) {
1661 Teuchos::Array<MagnitudeType> residualNorm;
1662 residualNorm = Utilities::ResidualNorm(A, X, B, *residual_[startLevel]);
1663
1664 const MagnitudeType currentResidualNorm = residualNorm[0];
1665 rate_ = currentResidualNorm / previousResidualNorm;
1666 previousResidualNorm = currentResidualNorm;
1667
1668 if (IsPrint(Statistics1))
1669 PrintResidualHistory(iteration, residualNorm);
1670
1671 return IsConverged(residualNorm, conv.tol_);
1672}
1673
1674} // namespace MueLu
1675
1676#endif // MUELU_HIERARCHY_DEF_HPP
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.
Provides methods to build a multigrid hierarchy and apply multigrid cycles.
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.
virtual ~Hierarchy()
Destructor.
void CheckLevel(Level &level, int levelID)
Helper function.
std::string description() const
Return a simple one-line description of this object.
void CheckForEmptySmoothersAndCoarseSolve()
void IsPreconditioner(const bool flag)
Array< RCP< Level > > Levels_
Container for Level objects.
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.
STS::magnitudeType MagnitudeType
void describe(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the Hierarchy with some verbosity level to a FancyOStream object.
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
void SetMatvecParams(RCP< ParameterList > matvecParams)
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.
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.
double GetOperatorComplexity() const
void PrintResidualHistory(const LO iteration, const Teuchos::Array< MagnitudeType > &residualNorm) const
Print residualNorm for this iteration to the screen.
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.
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.
void SetLabel(const std::string &hierarchyLabel)
void AddKeepFlag(const std::string &ename, const FactoryBase *factory=NoFactory::get(), KeepType keep=MueLu::Keep)
Call Level::AddKeepFlag for each level of the Hierarchy.
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.
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, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
static void SetRandomSeed(const Teuchos::Comm< int > &comm)
Set seed for random number generator.
static RCP< MultiVector > Residual(const Xpetra::Operator< Scalar, LocalOrdinal, GlobalOrdinal, Node > &Op, const MultiVector &X, const MultiVector &RHS)
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.