MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_HierarchyManager_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_HIERARCHYMANAGER_DEF_HPP
11#define MUELU_HIERARCHYMANAGER_DEF_HPP
12
13#include <string>
14#include <map>
15
16#include <Teuchos_Array.hpp>
17
18#include <Xpetra_Operator.hpp>
19#include <Xpetra_IO.hpp>
20
21#include "MueLu_ConfigDefs.hpp"
23
24#include "MueLu_Exceptions.hpp"
25#include "MueLu_Aggregates.hpp"
26#include "MueLu_Hierarchy.hpp"
28#include "MueLu_Level.hpp"
29#include "MueLu_MasterList.hpp"
30#include "MueLu_PerfUtils.hpp"
31
32#ifdef HAVE_MUELU_INTREPID2
33#include "Kokkos_DynRankView.hpp"
34#endif
35
36namespace MueLu {
37
38template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
40 : numDesiredLevel_(numDesiredLevel)
41 , maxCoarseSize_(MasterList::getDefault<int>("coarse: max size"))
42 , verbosity_(Medium)
43 , doPRrebalance_(MasterList::getDefault<bool>("repartition: rebalance P and R"))
44 , doPRViaCopyrebalance_(MasterList::getDefault<bool>("repartition: explicit via new copy rebalance P and R"))
45 , implicitTranspose_(MasterList::getDefault<bool>("transpose: use implicit"))
46 , fuseProlongationAndUpdate_(MasterList::getDefault<bool>("fuse prolongation and update"))
47 , suppressNullspaceDimensionCheck_(MasterList::getDefault<bool>("nullspace: suppress dimension check"))
48 , sizeOfMultiVectors_(MasterList::getDefault<int>("number of vectors"))
49 , graphOutputLevel_(-2) {}
50
51template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
52void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::AddFactoryManager(int startLevel, int numDesiredLevel, RCP<FactoryManagerBase> manager) {
53 const int lastLevel = startLevel + numDesiredLevel - 1;
54 if (levelManagers_.size() < lastLevel + 1)
55 levelManagers_.resize(lastLevel + 1);
56
57 for (int iLevel = startLevel; iLevel <= lastLevel; iLevel++)
58 levelManagers_[iLevel] = manager;
60
61template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
63 // NOTE: last levelManager is used for all the remaining levels
64 return (levelID >= levelManagers_.size() ? levelManagers_[levelManagers_.size() - 1] : levelManagers_[levelID]);
66
67template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
69 return levelManagers_.size();
70}
71
72template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
74 for (int i = 0; i < levelManagers_.size(); i++)
75 TEUCHOS_TEST_FOR_EXCEPTION(levelManagers_[i] == Teuchos::null, Exceptions::RuntimeError, "MueLu:HierarchyConfig::CheckConfig(): Undefined configuration for level:");
76}
78template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
79RCP<MueLu::Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CreateHierarchy() const {
80 return rcp(new Hierarchy());
81}
82
83template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
84RCP<MueLu::Hierarchy<Scalar, LocalOrdinal, GlobalOrdinal, Node>> MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::CreateHierarchy(const std::string& label) const {
85 return rcp(new Hierarchy(label));
86}
87
88template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
90 TEUCHOS_TEST_FOR_EXCEPTION(!H.GetLevel(0)->IsAvailable("A"), Exceptions::RuntimeError, "No fine level operator");
91
92 RCP<Level> l0 = H.GetLevel(0);
93 RCP<Operator> Op = l0->Get<RCP<Operator>>("A");
94
95 // Compare nullspace dimension to NumPDEs and throw/warn based on user input
96 if (l0->IsAvailable("Nullspace")) {
97 RCP<Matrix> A = Teuchos::rcp_dynamic_cast<Matrix>(Op);
98 if (A != Teuchos::null) {
99 RCP<MultiVector> nullspace = l0->Get<RCP<MultiVector>>("Nullspace");
101 if (static_cast<size_t>(A->GetFixedBlockSize()) > nullspace->getNumVectors()) {
102 std::stringstream msg;
103 msg << "User-provided nullspace has fewer vectors ("
104 << nullspace->getNumVectors() << ") than number of PDE equations ("
105 << A->GetFixedBlockSize() << "). ";
106
107 if (suppressNullspaceDimensionCheck_) {
108 msg << "It depends on the PDE, if this is a problem or not.";
109 this->GetOStream(Warnings0) << msg.str() << std::endl;
110 } else {
111 msg << "Add the missing nullspace vectors! (You can suppress this check. See the MueLu user guide for details.)";
112 TEUCHOS_TEST_FOR_EXCEPTION(static_cast<size_t>(A->GetFixedBlockSize()) > nullspace->getNumVectors(), Exceptions::RuntimeError, msg.str());
113 }
114 }
115 } else {
116 this->GetOStream(Warnings0) << "Skipping dimension check of user-supplied nullspace because user-supplied operator is not a matrix" << std::endl;
117 }
118 }
119
120#ifdef HAVE_MUELU_DEBUG
121 // Reset factories' data used for debugging
122 for (int i = 0; i < levelManagers_.size(); i++)
123 levelManagers_[i]->ResetDebugData();
124
125#endif
126
127 // Setup Matrix
128 // TODO: I should certainly undo this somewhere...
129
130 Xpetra::UnderlyingLib lib = Op->getDomainMap()->lib();
131 H.setlib(lib);
132
133 SetupOperator(*Op);
134 SetupExtra(H);
135
136 // Setup Hierarchy
137 H.SetMaxCoarseSize(maxCoarseSize_);
139 if (graphOutputLevel_ >= 0 || graphOutputLevel_ == -1)
140 H.EnableGraphDumping("dep_graph", graphOutputLevel_);
141
143 RCP<Matrix> Amat = rcp_dynamic_cast<Matrix>(Op);
144
145 if (!Amat.is_null()) {
146 RCP<ParameterList> params = rcp(new ParameterList());
147 params->set("printLoadBalancingInfo", true);
148 params->set("printCommInfo", true);
149
151 } else {
152 VerboseObject::GetOStream(Warnings1) << "Fine level operator is not a matrix, statistics are not available" << std::endl;
154 }
155
156 H.SetPRrebalance(doPRrebalance_);
157 H.SetPRViaCopyrebalance(doPRViaCopyrebalance_);
158 H.SetImplicitTranspose(implicitTranspose_);
159 H.SetFuseProlongationAndUpdate(fuseProlongationAndUpdate_);
160
161 H.Clear();
162
163 // There are few issues with using Keep in the interpreter:
164 // 1. Hierarchy::Keep interface takes a name and a factory. If
165 // factories are different on different levels, the AddNewLevel() call
166 // in Hierarchy does not work properly, as it assume that factories are
167 // the same.
168 // 2. FactoryManager does not have a Keep option, only Hierarchy and
169 // Level have it
170 // 3. Interpreter constructs factory managers, but not levels. So we
171 // cannot set up Keep flags there.
172 //
173 // The solution implemented here does the following:
174 // 1. Construct hierarchy with dummy levels. This avoids
175 // Hierarchy::AddNewLevel() calls which will propagate wrong
176 // inheritance.
177 // 2. Interpreter constructs keep_ array with names and factories for
178 // that level
179 // 3. For each level, we call Keep(name, factory) for each keep_
180 for (int i = 0; i < numDesiredLevel_; i++) {
181 std::map<int, std::vector<keep_pair>>::const_iterator it = keep_.find(i);
182 if (it != keep_.end()) {
183 RCP<Level> l = H.GetLevel(i);
184 const std::vector<keep_pair>& keeps = it->second;
185 for (size_t j = 0; j < keeps.size(); j++)
186 l->Keep(keeps[j].first, keeps[j].second);
187 }
188 if (i < numDesiredLevel_ - 1) {
189 RCP<Level> newLevel = rcp(new Level());
190 H.AddLevel(newLevel);
191 }
192 }
193
194 // Matrices to print
195 for (auto iter = matricesToPrint_.begin(); iter != matricesToPrint_.end(); iter++)
196 ExportDataSetKeepFlags(H, iter->second, iter->first);
197
198 // Vectors, aggregates and other things that need special case handling
199 ExportDataSetKeepFlags(H, nullspaceToPrint_, "Nullspace");
200 ExportDataSetKeepFlags(H, coordinatesToPrint_, "Coordinates");
201 ExportDataSetKeepFlags(H, materialToPrint_, "Material");
202 // NOTE: Aggregates use the next level's Factory
203 ExportDataSetKeepFlagsNextLevel(H, aggregatesToPrint_, "Aggregates");
204#ifdef HAVE_MUELU_INTREPID2
205 ExportDataSetKeepFlags(H, elementToNodeMapsToPrint_, "pcoarsen: element to node map");
206#endif
207
208 // Data to keep only (these do not have a level, so we do all levels)
209 for (int i = 0; i < dataToKeep_.size(); i++)
210 ExportDataSetKeepFlagsAll(H, dataToKeep_[i]);
211
212 int levelID = 0;
213 int lastLevelID = numDesiredLevel_ - 1;
214 bool isLastLevel = false;
215
216 while (!isLastLevel) {
217 bool r = H.Setup(levelID,
218 LvlMngr(levelID - 1, lastLevelID),
219 LvlMngr(levelID, lastLevelID),
220 LvlMngr(levelID + 1, lastLevelID));
221 if (levelID < H.GetNumLevels())
222 H.GetLevel(levelID)->print(H.GetOStream(Developer), verbosity_);
223
224 isLastLevel = r || (levelID == lastLevelID);
225 levelID++;
226 }
227 if (!matvecParams_.is_null())
228 H.SetMatvecParams(matvecParams_);
229 H.AllocateLevelMultiVectors(sizeOfMultiVectors_);
230 // Set hierarchy description.
231 // This is cached, but involves and MPI_Allreduce.
232 H.description();
233 H.describe(H.GetOStream(Runtime0), verbosity_);
235
236 // When we reuse hierarchy, it is necessary that we don't
237 // change the number of levels. We also cannot make requests
238 // for coarser levels, because we don't construct all the
239 // data on previous levels. For instance, let's say our first
240 // run constructed three levels. If we try to do requests during
241 // next setup for the fourth level, it would need Aggregates
242 // which we didn't construct for level 3 because we reused P.
243 // To fix this situation, we change the number of desired levels
244 // here.
245 numDesiredLevel_ = levelID;
246
247 // Matrix prints
248 for (auto iter = matricesToPrint_.begin(); iter != matricesToPrint_.end(); iter++) {
249 WriteData<Matrix>(H, iter->second, iter->first);
250 }
251
252 // Vectors, aggregates and all things we need to print manually
253 WriteData<MultiVector>(H, nullspaceToPrint_, "Nullspace");
254 WriteData<MultiVector>(H, coordinatesToPrint_, "Coordinates");
255 WriteData<MultiVector>(H, materialToPrint_, "Material");
256 WriteDataAggregates(H, aggregatesToPrint_, "Aggregates");
257
258#ifdef HAVE_MUELU_INTREPID2
259 typedef Kokkos::DynRankView<LocalOrdinal, typename Node::device_type> FCi;
260 WriteDataFC<FCi>(H, elementToNodeMapsToPrint_, "pcoarsen: element to node map", "el2node");
261#endif
262
263} // SetupHierarchy
264
265template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
266Teuchos::RCP<FactoryManagerBase> MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::LvlMngr(int levelID, int lastLevelID) const {
267 // NOTE: the order of 'if' statements is important
268 if (levelID == -1) // levelID = -1 corresponds to the finest level
269 return Teuchos::null;
270
271 if (levelID == lastLevelID + 1) // levelID = 'lastLevelID+1' corresponds to the last level (i.e., no nextLevel)
272 return Teuchos::null;
273
274 if (levelManagers_.size() == 0) { // default factory manager.
275 // The default manager is shared across levels, initialized only if needed and deleted with the HierarchyManager
276 static RCP<FactoryManagerBase> defaultMngr = rcp(new FactoryManager());
277 return defaultMngr;
278 }
279
280 return GetFactoryManager(levelID);
281}
282
283template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
284void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::ExportDataSetKeepFlags(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
285 for (int i = 0; i < data.size(); ++i) {
286 if (data[i] < H.GetNumLevels()) {
287 RCP<Level> L = H.GetLevel(data[i]);
288 if (!L.is_null() && data[i] < levelManagers_.size())
289 L->AddKeepFlag(name, &*levelManagers_[data[i]]->GetFactory(name));
290 }
291 }
292}
293
294template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
295void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::ExportDataSetKeepFlagsNextLevel(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
296 for (int i = 0; i < data.size(); ++i) {
297 if (data[i] < H.GetNumLevels()) {
298 RCP<Level> L = H.GetLevel(data[i]);
299 if (!L.is_null() && data[i] + 1 < levelManagers_.size())
300 L->AddKeepFlag(name, &*levelManagers_[data[i] + 1]->GetFactory(name));
301 }
302 }
303}
304
305template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
307 for (int i = 0; i < H.GetNumLevels(); i++) {
308 RCP<Level> L = H.GetLevel(i);
309 if (!L.is_null() && i < levelManagers_.size())
310 L->AddKeepFlag(name, &*levelManagers_[i]->GetFactory(name));
311 }
312}
313
314template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
315template <class T>
316void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteData(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
317 for (int i = 0; i < data.size(); ++i) {
318 std::string fileName;
319 if (H.getObjectLabel() != "")
320 fileName = H.getObjectLabel() + "_" + name + "_" + Teuchos::toString(data[i]) + ".m";
321 else
322 fileName = name + "_" + Teuchos::toString(data[i]) + ".m";
323
324 if (data[i] < H.GetNumLevels()) {
325 RCP<Level> L = H.GetLevel(data[i]);
326 if (data[i] < levelManagers_.size() && L->IsAvailable(name, &*levelManagers_[data[i]]->GetFactory(name))) {
327 // Try generating factory
328 RCP<T> M = L->template Get<RCP<T>>(name, &*levelManagers_[data[i]]->GetFactory(name));
329 if (!M.is_null()) {
330 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(fileName, *M);
331 }
332 } else if (L->IsAvailable(name)) {
333 // Try nofactory
334 RCP<T> M = L->template Get<RCP<T>>(name);
335 if (!M.is_null()) {
336 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Write(fileName, *M);
337 }
338 }
339 }
340 }
341}
342
343template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
344void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteDataAggregates(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name) const {
345 for (int i = 0; i < data.size(); ++i) {
346 const std::string fileName = name + "_" + Teuchos::toString(data[i]) + ".m";
347
348 if (data[i] < H.GetNumLevels()) {
349 RCP<Level> L = H.GetLevel(data[i]);
350
351 // NOTE: Aggregates use the next level's factory
352 RCP<Aggregates> agg;
353 if (data[i] + 1 < H.GetNumLevels() && L->IsAvailable(name, &*levelManagers_[data[i] + 1]->GetFactory(name))) {
354 // Try generating factory
355 agg = L->template Get<RCP<Aggregates>>(name, &*levelManagers_[data[i] + 1]->GetFactory(name));
356 } else if (L->IsAvailable(name)) {
357 agg = L->template Get<RCP<Aggregates>>("Aggregates");
358 }
359 if (!agg.is_null()) {
360 auto Vertex2AggId = agg->GetVertex2AggId();
361 Xpetra::IO<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteLOMV(fileName, *Vertex2AggId);
362 }
363 }
364 }
365}
366
367template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
368template <class T>
369void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteDataFC(Hierarchy& H, const Teuchos::Array<int>& data, const std::string& name, const std::string& ofname) const {
370 for (int i = 0; i < data.size(); ++i) {
371 const std::string fileName = ofname + "_" + Teuchos::toString(data[i]) + ".m";
372
373 if (data[i] < H.GetNumLevels()) {
374 RCP<Level> L = H.GetLevel(data[i]);
375
376 if (L->IsAvailable(name)) {
377 RCP<T> M = L->template Get<RCP<T>>(name);
378 if (!M.is_null()) {
379 RCP<Matrix> A = L->template Get<RCP<Matrix>>("A");
380 RCP<const CrsGraph> AG = A->getCrsGraph();
381 WriteFieldContainer<T>(fileName, *M, *AG->getColMap());
382 }
383 }
384 }
385 }
386}
387
388template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
389template <class T>
390void MueLu::HierarchyManager<Scalar, LocalOrdinal, GlobalOrdinal, Node>::WriteFieldContainer(const std::string& fileName, T& fcont, const Map& colMap) const {
391 size_t num_els = (size_t)fcont.extent(0);
392 size_t num_vecs = (size_t)fcont.extent(1);
393
394 // Generate rowMap
395 Teuchos::RCP<const Map> rowMap = Xpetra::MapFactory<LO, GO, NO>::Build(colMap.lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(), fcont.extent(0), colMap.getIndexBase(), colMap.getComm());
396
397 // Fill multivector to use *petra dump routines
398 RCP<GOMultiVector> vec = Xpetra::MultiVectorFactory<GO, LO, GO, NO>::Build(rowMap, num_vecs);
399
400 for (size_t j = 0; j < num_vecs; j++) {
401 Teuchos::ArrayRCP<GO> v = vec->getDataNonConst(j);
402 for (size_t i = 0; i < num_els; i++)
403 v[i] = colMap.getGlobalElement(fcont(i, j));
404 }
405
406 Xpetra::IO<SC, LO, GO, NO>::WriteGOMV(fileName, *vec);
407}
408
409} // namespace MueLu
410
411#endif
Exception throws to report errors in the internal logical of the program.
This class specifies the default factory that should generate some data on a Level if the data does n...
void WriteFieldContainer(const std::string &fileName, T &fcont, const Map &colMap) const
void ExportDataSetKeepFlagsNextLevel(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
void ExportDataSetKeepFlags(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
void WriteDataFC(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name, const std::string &ofname) const
void WriteData(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
RCP< FactoryManagerBase > GetFactoryManager(int levelID) const
void WriteDataAggregates(Hierarchy &H, const Teuchos::Array< int > &data, const std::string &name) const
void AddFactoryManager(int startLevel, int numDesiredLevel, RCP< FactoryManagerBase > manager)
virtual void SetupHierarchy(Hierarchy &H) const
Setup Hierarchy object.
virtual RCP< Hierarchy > CreateHierarchy() const
Create an empty Hierarchy object.
void ExportDataSetKeepFlagsAll(Hierarchy &H, const std::string &name) const
HierarchyManager(int numDesiredLevel=MasterList::getDefault< int >("max levels"))
Constructor.
Teuchos::RCP< FactoryManagerBase > LvlMngr(int levelID, int lastLevelID) const
size_t getNumFactoryManagers() const
returns number of factory managers stored in levelManagers_ vector.
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.
RCP< Level > & GetLevel(const int levelID=0)
Retrieve a certain level from hierarchy.
std::string description() const
Return a simple one-line description of this object.
void CheckForEmptySmoothersAndCoarseSolve()
void setlib(Xpetra::UnderlyingLib inlib)
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 SetFuseProlongationAndUpdate(const bool &fuse)
void describe(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the Hierarchy with some verbosity level to a FancyOStream object.
void SetPRrebalance(bool doPRrebalance)
void SetPRViaCopyrebalance(bool doPRViaCopyrebalance)
void SetMatvecParams(RCP< ParameterList > matvecParams)
void Clear(int startLevel=0)
Clear impermanent data from previous setup.
void EnableGraphDumping(const std::string &filename, int levelID=1)
void SetMaxCoarseSize(Xpetra::global_size_t maxCoarseSize)
void AllocateLevelMultiVectors(int numvecs, bool forceMapCheck=false)
void SetImplicitTranspose(const bool &implicit)
Class that holds all level-specific information.
Static class that holds the complete list of valid MueLu parameters.
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
static void SetDefaultVerbLevel(const VerbLevel defaultVerbLevel)
Set the default (global) verbosity level.
Namespace for MueLu classes and methods.
@ Warnings0
Important warning messages (one line)
@ Statistics2
Print even more statistics.
@ Developer
Print information primarily of interest to developers.
@ Runtime0
One-liner description of what is happening.
@ Warnings1
Additional warnings.