MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_Level.cpp
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#include <Teuchos_TabularOutputter.hpp>
11
12#include "MueLu_Level.hpp"
13
15
16namespace MueLu {
17
19 : lib_(Xpetra::NotSpecified)
20 , levelID_(-1) {}
21
22Level::Level(RCP<FactoryManagerBase>& factoryManager)
23 : lib_(Xpetra::UseTpetra)
24 , levelID_(-1)
25 , factoryManager_(factoryManager) {}
26
27Level::~Level() = default;
28
29RCP<Level> Level::Build() {
30 RCP<Level> newLevel = rcp(new Level());
31
32 // Copy 'keep' status of variables
33 for (TwoKeyMap::const_iterator kt = map_.begin(); kt != map_.end(); kt++) {
34 const FactoryBase* factory = kt->first;
35
36 for (SubMap::const_iterator it = kt->second.begin(); it != kt->second.end(); it++) {
37 const std::string& ename = it->first;
38
39 if (IsKept(ename, factory, MueLu::Keep)) { // MueLu::Keep is the only flag propagated
40 if (factory == NULL) // TODO: Is this possible?? Throw exception. Not supposed to use the FactoryManager here.
41 newLevel->Keep(ename, NoFactory::get());
42 else
43 newLevel->Keep(ename, factory);
44 }
45 }
46 }
47
48 return newLevel;
49}
50
51int Level::GetLevelID() const { return levelID_; }
52
53void Level::SetLevelID(int levelID) {
54 if (levelID_ != -1 && levelID_ != levelID)
55 GetOStream(Warnings1) << "Level::SetLevelID(): Changing an already defined LevelID (previousID=" << levelID_ << ", newID=" << levelID << ")" << std::endl;
56
57 levelID_ = levelID;
58}
59
60RCP<Level>& Level::GetPreviousLevel() { return previousLevel_; }
61
62void Level::SetPreviousLevel(const RCP<Level>& previousLevel) {
63 if (previousLevel_ != Teuchos::null && previousLevel_ != previousLevel)
64 GetOStream(Warnings1) << "Level::SetPreviousLevel(): PreviousLevel was already defined" << std::endl;
65
66 previousLevel_ = previousLevel;
67}
68
69void Level::SetFactoryManager(const RCP<const FactoryManagerBase>& factoryManager) {
70 factoryManager_ = factoryManager;
71}
72
73const RCP<const FactoryManagerBase> Level::GetFactoryManager() {
74 return factoryManager_;
75}
76
77std::string Level::GetTypeName(const std::string& ename, const FactoryBase* factory) {
78 const FactoryBase* fac = GetFactory(ename, factory);
79 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(fac, ename), Exceptions::RuntimeError, "\"" + ename + "\" not found");
80
81 TEUCHOS_TEST_FOR_EXCEPTION(!IsAvailable(ename, fac), Exceptions::RuntimeError,
82 "MueLu::Level::GetTypeString(): Data "
83 "\"" << ename
84 << "\" generated by " << *fac << " is not available.");
85
86 return map_[fac][ename]->GetTypeName();
87}
88
89void Level::Delete(const std::string& ename, const FactoryBase* factory) { // Note: do not add default value for input parameter 'factory'
90 if (!IsKey(factory, ename))
91 return;
92
93 // Precondition:
94 // Delete() should only be called if counter == 0
95 // Note: It better to throw an exception rather than deleting the data if counter != 0 because users are not supposed to manipulate data with counter != 0
96 TEUCHOS_TEST_FOR_EXCEPTION(IsRequested(ename, factory) == true, Exceptions::RuntimeError, "MueLu::Level::Delete(): IsRequested() == true. Ref counter != 0. You are not allowed to delete data that are still in use.");
97 // If counter == 0 and entry exists, this means that a keep flag is set. Or there is an internal logic problem.
98 TEUCHOS_TEST_FOR_EXCEPTION(GetKeepFlag(ename, factory) == 0, Exceptions::RuntimeError, "MueLu::Level::Delete(), Keep flag == 0?");
99
100 RemoveKeepFlag(ename, factory, MueLu::All); // will delete the data if counter == 0
101
102 // Post condition: data must have been deleted
103 TEUCHOS_TEST_FOR_EXCEPTION(IsAvailable(ename, factory) == true, Exceptions::RuntimeError, "MueLu::Level::Delete(): Internal error (Post condition). Data have not been deleted.");
104}
105
106void Level::AddKeepFlag(const std::string& ename, const FactoryBase* factory, KeepType keep) {
107 if (!IsKey(factory, ename)) {
108 // If the entry does not exist, create it to store the keep flag
109 Teuchos::RCP<MueLu::VariableContainer> newVar = Teuchos::rcp(new MueLu::VariableContainer);
110 map_[factory][ename] = newVar;
111 }
112 // Set the flag
113 map_[factory][ename]->AddKeepFlag(keep);
114}
115
116void Level::RemoveKeepFlag(const std::string& ename, const FactoryBase* factory, KeepType keep) {
117 // No entry = nothing to do
118 if (!IsKey(factory, ename))
119 return;
120
121 // Remove the flag
122 Teuchos::RCP<MueLu::VariableContainer>& v = map_[factory][ename];
123 v->RemoveKeepFlag(keep);
124
125 // Remove data if no keep flag left and counter == 0
126 if ((v->IsRequested() == false) && (v->GetKeepFlag() == 0)) {
127 v = Teuchos::null; // free data
128
129 map_[factory].erase(ename);
130 if (map_.count(factory) == 0)
131 map_.erase(factory);
132 }
133}
134
135KeepType Level::GetKeepFlag(const std::string& ename, const FactoryBase* factory) const {
136 if (!IsKey(factory, ename))
137 return false;
138
139 return Get(factory, ename)->GetKeepFlag();
140}
141
142void Level::Request(const FactoryBase& factory) {
145 factory.CallDeclareInput(*this);
146 requestMode_ = prev;
147}
148
149void Level::Release(const FactoryBase& factory) {
152 factory.CallDeclareInput(*this);
153 requestMode_ = prev;
154}
155
156void Level::DeclareInput(const std::string& ename, const FactoryBase* factory, const FactoryBase* requestedBy) {
157 if (requestMode_ == REQUEST) {
158 try {
159 Request(ename, factory, requestedBy);
160
161 } catch (Exceptions::DependencyError& e) {
162 std::ostringstream msg;
163 msg << requestedBy->ShortClassName() << "::DeclareInput: (" << e.what() << ") unable to find or generate requested data \""
164 << ename << "\" with generating factory \"" << ((factory != NULL) ? factory->ShortClassName() : "null") << "\" [" << factory << "]";
165 msg << "\n during request for data \"" << std::setw(15) << ename << "\" on level " << GetLevelID()
166 << " by factory " << std::setw(25) << requestedBy->ShortClassName() << " [" << requestedBy << "]";
167 throw Exceptions::RuntimeError(msg.str());
168
169 } catch (Exceptions::RuntimeError& e) {
170 std::ostringstream msg;
171 msg << e.what() << "\n during request for data \"" << std::setw(15) << ename << "\" on level " << GetLevelID()
172 << " by factory " << std::setw(25) << requestedBy->ShortClassName() << " [" << requestedBy << "]";
173 throw Exceptions::RuntimeError(msg.str());
174 }
175
176 } else if (requestMode_ == RELEASE) {
177 Release(ename, factory, requestedBy);
178
179 } else
180 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::Level::DeclareInput(): requestMode_ undefined.");
181}
182
183void Level::DeclareDependencies(const FactoryBase* factory, bool bRequestOnly, bool bReleaseOnly) { // TODO: replace bReleaseOnly, bReleaseOnly by one RequestMode enum
184 if (bRequestOnly && bReleaseOnly)
185 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::Level::DeclareDependencies(): Both bRequestOnly and bReleaseOnly set to true makes no sense.");
186
187 if (requestMode_ == REQUEST) {
188 if (bReleaseOnly == false) Request(*factory);
189
190 } else if (requestMode_ == RELEASE) {
191 if (bRequestOnly == false) Release(*factory);
192
193 } else
194 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::Level::DeclareDependencies(): requestMode_ undefined.");
195}
196
197void Level::Request(const std::string& ename, const FactoryBase* factory, const FactoryBase* requestedBy) {
198 const FactoryBase* fac = GetFactory(ename, factory);
199 // printf("(l=%d) [%43s] requesting \"%20s\" generated by %10p [actually, generated by %p (%43s)]\n",
200 // levelID_, requestedBy->description().c_str(), ename.c_str(), factory, fac, fac->description().c_str());
201
202 // We request factory only if necessary, i.e.
203 // - factory has not been requested before, and
204 // - we need data which is not available
205 // Let us consider an RAP factory in the reuse scenario. The factory generates "A" (coarse matrix) and
206 // "RAP graph" (pattern of A). Typically, "A" has keep flag Final, which is cleared during next Setup, but
207 // "RAP graph" has flag Keep, which is not cleared as it is part of NextRun. Therefore, during next Setup
208 // we have RAP factory with available "RAP graph" but not available "A".
209 //
210 // During the regular construction phase, we will do a single request: ("A", RAPFactory). Suppose, we used
211 // bool test = (IsRequestedFactory(fac) == false && IsAvailable(fac) == false);
212 // This is incorrect, as IsAvailable(fac) checks whether there is *any* data generated by factory, which there is
213 // ("A"), and the dependencies of the factory would not be requested despite the need for them (we need fine A, P, and
214 // R to generate Ac even if we know sparsity pattern of Ac).
215 //
216 // On the other hand,
217 // bool test = (IsRequestedFactory(fac) == false && IsAvailable(ename, fac) == false);
218 // is correct as ("A", fac) is not available (only ("RAP graph", fac) is), and dependent factories would be
219 // properly requested.
220 //
221 // This way, factory is requested only once (because of the IsRequested(fac) check), and only when one of the needed
222 // pieces of data is not availble.
223 bool test = (IsRequestedFactory(fac) == false && IsAvailable(ename, fac) == false);
224
225 // This request must be done before calling Request(*fac) to avoid circular dependency problems.
226 if (!IsKey(fac, ename)) {
227 Teuchos::RCP<MueLu::VariableContainer> newVar = Teuchos::rcp(new MueLu::VariableContainer);
228 map_[fac][ename] = newVar;
229 }
230
231 Teuchos::RCP<MueLu::VariableContainer>& v = map_[fac][ename];
232 v->Request(requestedBy);
233
234 // The value of IsRequestedFactory(fac) is true, due to the above request.
235 // That is why a temporary boolean "test" is used!
236 TEUCHOS_TEST_FOR_EXCEPTION(IsRequestedFactory(fac) != true, Exceptions::RuntimeError, "Level::Request(ename, factory): internal logic error.");
237
238 if (test) {
239 // Call Request for factory dependencies.
240 // We only do that if necessary, see comments above
241 Request(*fac);
242 }
243}
244
245void Level::Release(const std::string& ename, const FactoryBase* factory, const FactoryBase* requestedBy) {
246 const FactoryBase* fac = GetFactory(ename, factory);
247 // printf("(l=%d) [%43s] releasing \"%20s\" generated by %10p [actually, generated by %p (%43s)]\n",
248 // levelID_, requestedBy->description().c_str(), ename.c_str(), factory, fac, fac->description().c_str());
249
250 // Only a factory which has requested (fac,ename) is allowed to release it again.
251 // Do not release data if it has not been requested by the factory "requestedBy"
252 // Note: when data is released (fac,ename) depends on it often happened that some
253 // of this data has (recursively) been released too often
254 if (IsRequestedBy(fac, ename, requestedBy)) {
255 // In general all data (fac,ename) depends on is released when calling Get in generating factory (fac) Build method
256 // Here we check the need to release the dependencies of some data that has been requested (by factory "requestedBy")
257 // but the corresponding Build function of factory "fac" has never been called. Therefore the dependencies
258 // have never been released. Do it now.
259 if (CountRequestedFactory(fac) == 1 && // check if factory fac is not requested by another factory
260 IsAvailableFactory(fac) == false) { // check if Build function of factory fac has been called
261 Release(*fac);
262 }
263
264 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(fac, ename), Exceptions::RuntimeError, "\"" + ename + "\" not found. Do a request first.");
265
266 Teuchos::RCP<MueLu::VariableContainer>& v = map_[fac][ename];
267 v->Release(requestedBy);
268
269 // Remove data if no keep flag left and counter == 0
270 if ((v->IsRequested() == false) && (v->GetKeepFlag() == 0)) {
271 v = Teuchos::null; // free data
272
273 map_[fac].erase(ename);
274 if (map_.count(fac) == 0)
275 map_.erase(fac);
276 }
277 }
278}
279
281bool Level::IsAvailable(const std::string& ename, const FactoryBase* factory) const {
282 if (!IsKey(factory, ename))
283 return false;
284 try {
285 return Get(factory, ename)->IsAvailable();
286 } catch (...) {
287 return false;
288 }
289}
290
292bool Level::IsRequested(const std::string& ename, const FactoryBase* factory) const {
293 if (!IsKey(factory, ename))
294 return false;
295 try {
296 return IsRequested(Get(factory, ename));
297 } catch (...) {
298 return false;
299 }
300}
301
303 // TODO: needs some love, ugly as it is
304 // The ugliness is the fact that we restart both loops when we remove a single element
305 bool wasRemoved;
306 do {
307 wasRemoved = false;
308 for (TwoKeyMap::const_iterator kt = map_.begin(); kt != map_.end(); kt++) {
309 const FactoryBase* factory = kt->first;
310
311 for (SubMap::const_iterator it = kt->second.begin(); it != kt->second.end(); it++) {
312 // We really want a reference here, but because later we'll need to check whether the
313 // key was removed, we should copy the value
314 const std::string ename = it->first;
315
316 // We clear all the data that
317 // a) has not been requested
318 // b) is not being kept using NextRun (e.g., we clear out Final data)
319 if (!IsKept(ename, factory, MueLu::NextRun)) {
320 RemoveKeepFlag(ename, factory, MueLu::All); // will delete the data if counter == 0
321
322 // To prevent infinite looping, we need to check whether we have
323 // actually removed the data. In buggy code it may happen that we
324 // were unable to do that, for instance, if the data was outstanding
325 // request
326 if (IsKey(factory, ename)) {
327 GetOStream(Errors) << "Level::Clear found Internal data inconsistency" << std::endl;
328 print(GetOStream(Errors), VERB_EXTREME);
329
330 throw Exceptions::RuntimeError("Level::Clear found Internal data inconsistency");
331 }
332
333 wasRemoved = true;
334 break;
335 }
336 }
337
338 if (wasRemoved)
339 break;
340 }
341
342 } while (wasRemoved == true);
343}
344
346 TwoKeyMap::const_iterator kt = map_.begin();
347 while (kt != map_.end()) {
348 const FactoryBase* factory = kt->first;
349
350 SubMap::const_iterator it = kt->second.begin();
351 while (it != kt->second.end()) {
352 const std::string& ename = it->first;
353
354 // obtain variable container
355 Teuchos::RCP<MueLu::VariableContainer>& v = map_[factory][ename];
356
357 if (v->GetKeepFlag() == 0 ||
358 v->IsKept(MueLu::UserData) == true ||
359 v->IsKept(MueLu::Final) == true) {
360 it++;
361 v = Teuchos::null; // free data
362 map_[factory].erase(ename);
363 if (map_.count(factory) == 0) {
364 break; // last occurrence for factory has been removed. proceed with next factory
365 }
366 } else
367 it++;
368 } // end for it
369
370 if (map_.count(factory) == 0) {
371 kt++;
372 map_.erase(factory);
373 } else
374 kt++;
375 }
376}
377
378std::string Level::description() const {
379 std::ostringstream out;
380 out << BaseClass::description();
381 out << "{ levelID = " << levelID_ << "}";
382 return out.str();
383}
384
385void Level::print(std::ostream& out, const VerbLevel verbLevel) const {
386 if (!(verbLevel & Debug))
387 return;
388
389 out << "LevelID = " << GetLevelID() << std::endl;
390
391 typedef Teuchos::TabularOutputter TTO;
392 TTO outputter(out);
393 outputter.pushFieldSpec("data name", TTO::STRING, TTO::LEFT, TTO::GENERAL, 20);
394 outputter.pushFieldSpec("gen. factory addr.", TTO::STRING, TTO::LEFT, TTO::GENERAL, 40);
395 outputter.pushFieldSpec("req", TTO::INT, TTO::LEFT, TTO::GENERAL, 3);
396 outputter.pushFieldSpec("keep", TTO::STRING, TTO::LEFT, TTO::GENERAL, 5);
397 outputter.pushFieldSpec("type", TTO::STRING, TTO::LEFT, TTO::GENERAL, 18);
398 outputter.pushFieldSpec("data", TTO::STRING, TTO::LEFT, TTO::GENERAL, 14);
399 outputter.pushFieldSpec("req'd by", TTO::STRING, TTO::LEFT, TTO::GENERAL, 20);
400 outputter.outputHeader();
401
402 for (TwoKeyMap::const_iterator kt = map_.begin(); kt != map_.end(); kt++) {
403 const FactoryBase* factory = kt->first;
404
405 for (SubMap::const_iterator it = kt->second.begin(); it != kt->second.end(); it++) {
406 const std::string& ename = it->first;
407
408 outputter.outputField(ename); // variable name
409
410 // NOTE: We cannot dereference the factory pointer and call factory->description() as we do not know
411 // if the factory still exist (the factory pointer is a raw pointer by design). Instead, the level
412 // should store the factory description internally as a string for debugging purpose (and in debug mode only).
413 // // factory name
414 // std::stringstream ss1;
415 // ss1 << (*kt)->description();
416 // outputter.outputField((ss1.str()).substr(0,30));
417 if (factory == 0) {
418 outputter.outputField("Null");
419 } else if (factory == NoFactory::get()) {
420 outputter.outputField("NoFactory");
421 } else {
422 std::ostringstream oss;
423 oss << factory->ShortClassName() << "[" << factory->GetID() << "]";
424#ifdef HAVE_MUELU_DEBUG
425 oss << "(" << factory << ")";
426#endif
427 outputter.outputField(oss.str());
428 }
429
430 int reqcount = NumRequests(factory, ename); // request counter
431 outputter.outputField(reqcount);
432
433 KeepType keepType = GetKeepFlag(ename, factory);
434 if (keepType != 0) {
435 std::stringstream ss;
436 if (keepType & MueLu::UserData) {
437 ss << "User";
438 }
439 if (keepType & MueLu::Keep) {
440 ss << "Keep";
441 }
442 if (keepType & MueLu::Final) {
443 ss << "Final";
444 }
445 outputter.outputField(ss.str());
446 } else {
447 outputter.outputField("No");
448 }
449
450 if (IsAvailable(ename, factory)) {
451 std::string strType = it->second->GetTypeName();
452
453 if (strType == "int") {
454 outputter.outputField(strType);
455 outputter.outputField(it->second->GetData<int>());
456 } else if (strType == "double") {
457 outputter.outputField(strType);
458 outputter.outputField(it->second->GetData<double>());
459 } else if (strType == "string") {
460 outputter.outputField(strType);
461 outputter.outputField(it->second->GetData<std::string>());
462 } else {
463 size_t npos = std::string::npos;
464
465 if (strType.find("MueLu::Aggregates") != npos)
466 outputter.outputField("Aggregates");
467 else if (strType.find("MueLu::AmalgamationInfo") != npos)
468 outputter.outputField("AmalgamationInfo");
469 else if (strType.find("MueLu::Constraint") != npos)
470 outputter.outputField("Constraint");
471 else if (strType.find("MueLu::SmootherBase") != npos)
472 outputter.outputField("SmootherBase");
473 else if (strType.find("MueLu::SmootherPrototype") != npos)
474 outputter.outputField("SmootherPrototype");
475 else if (strType.find("Xpetra::Export") != npos)
476 outputter.outputField("Export");
477 else if (strType.find("Xpetra::Import") != npos)
478 outputter.outputField("Import");
479 else if (strType.find("Xpetra::Map") != npos)
480 outputter.outputField("Map");
481 else if (strType.find("Xpetra::Matrix") != npos)
482 outputter.outputField("Matrix");
483 else if (strType.find("Xpetra::MultiVector") != npos)
484 outputter.outputField("Vector");
485 else if (strType.find("Xpetra::Operator") != npos)
486 outputter.outputField("Operator");
487 else
488 outputter.outputField(strType);
489
490 outputter.outputField("available");
491 }
492
493 } else {
494 outputter.outputField("unknown");
495 outputter.outputField("not available");
496 }
497
498 typedef VariableContainer::request_container container_type;
499 const container_type& requestedBy = it->second->Requests();
500 std::ostringstream ss;
501 for (container_type::const_iterator ct = requestedBy.begin(); ct != requestedBy.end(); ct++) {
502 if (ct != requestedBy.begin()) ss << ",";
503 ss << ct->first->ShortClassName() << "[" << ct->first->GetID() << "]";
504#ifdef HAVE_MUELU_DEBUG
505 ss << "(" << ct->first << ")";
506#endif
507
508 if (ct->second > 1) ss << "x" << ct->second;
509 }
510 outputter.outputField(ss.str());
511
512 outputter.nextRow();
513 }
514 } // for (TwoKeyMap::const_iterator kt = map_.begin(); kt != map_.end(); kt++) {
515}
516
517#if defined(HAVE_MUELU_BOOST) && defined(HAVE_MUELU_BOOST_FOR_REAL) && defined(BOOST_VERSION) && (BOOST_VERSION >= 104400)
518void Level::UpdateGraph(std::map<const FactoryBase*, BoostVertex>& vindices,
519 std::map<std::pair<BoostVertex, BoostVertex>, std::string>& edges,
520 BoostProperties& dp,
521 BoostGraph& graph) const {
522 size_t vind = vindices.size();
523
524 for (TwoKeyMap::const_iterator it1 = map_.begin(); it1 != map_.end(); it1++) {
525 if (vindices.find(it1->first) == vindices.end()) {
526 BoostVertex boost_vertex = boost::add_vertex(graph);
527 std::ostringstream oss;
528 oss << it1->first->ShortClassName() << "[" << it1->first->GetID() << "]";
529 boost::put("label", dp, boost_vertex, oss.str());
530 vindices[it1->first] = vind++;
531 }
532
533 for (SubMap::const_iterator it2 = it1->second.begin(); it2 != it1->second.end(); it2++) {
534 const VariableContainer::request_container& requests = it2->second->Requests();
535 for (VariableContainer::request_container::const_iterator rit = requests.begin(); rit != requests.end(); rit++) {
536 if (vindices.find(rit->first) == vindices.end()) {
537 // requested by factory which is unknown
538 BoostVertex boost_vertex = boost::add_vertex(graph);
539 std::ostringstream oss;
540 oss << rit->first->ShortClassName() << "[" << rit->first->GetID() << "]";
541 boost::put("label", dp, boost_vertex, oss.str());
542 vindices[rit->first] = vind++;
543 }
544
545 edges[std::pair<BoostVertex, BoostVertex>(vindices[rit->first], vindices[it1->first])] = it2->first;
546 }
547 }
548 }
549}
550#endif
551
552// JG Note: should the option IgnoreUserData() moved to the Factory interface or on the specific factories that are using this option? It would simplify the level class.
553const FactoryBase* Level::GetFactory(const std::string& ename, const FactoryBase* factory) const {
554 if (factory != NULL)
555 return factory;
556
557 // If IgnoreUserData == false and if variable "ename" generated by NoFactory is provided by the user (MueLu::UserData),
558 // use user-provided data by default without querying the FactoryManager.
559 // When FactoryManager == null, we consider that IgnoreUserData == false.
560 if ((factoryManager_ == Teuchos::null || factoryManager_->IgnoreUserData() == false) &&
562 return NoFactory::get();
563 }
564
565 // Query factory manager
566 TEUCHOS_TEST_FOR_EXCEPTION(factoryManager_ == null, Exceptions::RuntimeError, "MueLu::Level(" << levelID_ << ")::GetFactory(" << ename << ", " << factory << "): No FactoryManager");
567 const FactoryBase* fac = factoryManager_->GetFactory(ename).get();
568 TEUCHOS_TEST_FOR_EXCEPTION(fac == NULL, Exceptions::RuntimeError, "MueLu::Level(" << levelID_ << ")::GetFactory(" << ename << ", " << factory << "): Default factory returned by FactoryManager cannot be NULL");
569 return fac;
570}
571
572bool Level::IsKey(const FactoryBase* factory, const std::string& ename) const {
573 TwoKeyMap::const_iterator it = map_.find(factory);
574 return (it != map_.end()) ? (it->second).count(ename) : false;
575}
576
577bool Level::IsAvailableFactory(const FactoryBase* factory) const {
578 TwoKeyMap::const_iterator it = map_.find(factory);
579 if (it == map_.end())
580 return false;
581 for (SubMap::const_iterator sit = it->second.begin(); sit != it->second.end(); sit++) {
582 if (sit->second->IsAvailable())
583 return true;
584 }
585 return false;
586}
587
588bool Level::IsRequested(const Value& v) const {
589 TEUCHOS_TEST_FOR_EXCEPTION(v->NumAllRequests() == 0 && v->GetKeepFlag() == 0, Exceptions::RuntimeError,
590 "Internal logic error: if counter == 0, the entry in countTable_ should have been deleted");
591 return v->IsRequested();
592}
593
594bool Level::IsRequestedBy(const FactoryBase* factory, const std::string& ename, const FactoryBase* requestedBy) const {
595 if (!IsKey(factory, ename))
596 return false;
597
598 return IsRequestedBy(Get(factory, ename), requestedBy);
599}
600
601bool Level::IsRequestedBy(const Value& v, const FactoryBase* requestedBy) const {
602 TEUCHOS_TEST_FOR_EXCEPTION(v->NumAllRequests() == 0 && v->GetKeepFlag() == 0, Exceptions::RuntimeError,
603 "Internal logic error: if counter == 0, the entry in countTable_ should have been deleted");
604 return v->IsRequested(requestedBy);
605}
606
607bool Level::IsRequestedFactory(const FactoryBase* factory) const {
608 TwoKeyMap::const_iterator it = map_.find(factory);
609 if (it == map_.end())
610 return false;
611 for (SubMap::const_iterator sit = it->second.begin(); sit != it->second.end(); sit++)
612 if (IsRequested(sit->second))
613 return true;
614 return false;
615}
616
617const RCP<VariableContainer>& Level::Get(const FactoryBase* factory, const std::string& ename) const {
618 TwoKeyMap::const_iterator it = map_.find(factory);
619 TEUCHOS_TEST_FOR_EXCEPTION(it == map_.end(), Exceptions::RuntimeError, "Key (" << factory << ", *) does not exist.");
620
621 SubMap::const_iterator sit = it->second.find(ename);
622 TEUCHOS_TEST_FOR_EXCEPTION(sit == it->second.end(), Exceptions::RuntimeError, "Key (" << factory << ", " << ename << ") does not exist.");
623
624 return sit->second;
625}
626
627int Level::NumRequests(const FactoryBase* factory, const std::string& ename) const {
628 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(factory, ename), Exceptions::RuntimeError, "\"" + ename + "\" not found. Do a request first.");
629 const Teuchos::RCP<MueLu::VariableContainer>& v = Get(factory, ename);
630 TEUCHOS_TEST_FOR_EXCEPTION(v->NumAllRequests() == 0 && v->GetKeepFlag() == 0, Exceptions::RuntimeError,
631 "NumRequests(): Internal logic error: if counter == 0, the entry in countTable_ should have been deleted");
632 return v->NumAllRequests();
633}
634
635int Level::CountRequestedFactory(const FactoryBase* factory) const {
636 TwoKeyMap::const_iterator it = map_.find(factory);
637 if (it == map_.end())
638 return 0;
639
640 int cnt = 0;
641 for (SubMap::const_iterator sit = it->second.begin(); sit != it->second.end(); sit++)
642 cnt += sit->second->NumAllRequests();
643
644 return cnt;
645}
646
648
649} // namespace MueLu
650
651// TODO: Caps should not matter
virtual std::string ShortClassName() const
Return the class name of the object, without template parameters and without namespace.
virtual std::string description() const
Return a simple one-line description of this object.
Exception throws to report data dependency problems between factories.
Exception throws to report errors in the internal logical of the program.
Base class for factories (e.g., R, P, and A_coarse).
virtual void CallDeclareInput(Level &requestedLevel) const =0
int GetID() const
return unique factory id
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
const FactoryBase * GetFactory(const std::string &varname, const FactoryBase *factory) const
If input factory == NULL, returns the default factory. Else, return input factory.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
RCP< Level > Build()
std::string description() const
Return a simple one-line description of this object.
RCP< Level > & GetPreviousLevel()
Previous level.
static RequestMode requestMode_
void Release(const FactoryBase &factory)
Decrement the storage counter for all the inputs of a factory.
int CountRequestedFactory(const FactoryBase *factory) const
const RCP< const FactoryManagerBase > GetFactoryManager()
returns the current factory manager
void SetLevelID(int levelID)
Set level number.
void print(std::ostream &out, const VerbLevel verbLevel=Default) const
Printing method.
RCP< Level > previousLevel_
void RemoveKeepFlag(const std::string &ename, const FactoryBase *factory, KeepType keep=MueLu::All)
int GetLevelID() const
Return level number.
std::string GetTypeName(const std::string &ename, const FactoryBase *factory=NoFactory::get())
GetTypeName returns type string of variable stored using ename and factory.
RCP< VariableContainer > Value
void Clear()
Delete all data that have been retained after the setup phase using Final flag.
void AddKeepFlag(const std::string &ename, const FactoryBase *factory=NoFactory::get(), KeepType keep=MueLu::Keep)
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
void DeclareDependencies(const FactoryBase *factory, bool bRequestOnly=false, bool bReleaseOnly=false)
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput() to declare factory depe...
bool IsRequestedFactory(const FactoryBase *factory) const
KeepType GetKeepFlag(const std::string &ename, const FactoryBase *factory) const
Get the flag combination set for variable 'ename' generated by 'factory'.
RCP< const FactoryManagerBase > factoryManager_
bool IsKept(const std::string &ename, const FactoryBase *factory, KeepType keep) const
bool IsAvailableFactory(const FactoryBase *factory) const
virtual ~Level()
Destructor.
bool IsRequested(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need has been requested. Note: this tells nothing about whether the need's value exist...
int NumRequests(const FactoryBase *factory, const std::string &ename) const
void Request(const FactoryBase &factory)
Increment the storage counter for all the inputs of a factory.
bool IsRequestedBy(const FactoryBase *factory, const std::string &ename, const FactoryBase *requestedBy) const
void SetPreviousLevel(const RCP< Level > &previousLevel)
void SetFactoryManager(const RCP< const FactoryManagerBase > &factoryManager)
Set default factories (used internally by Hierarchy::SetLevel()).
int levelID_
Map of a map (Key1 -> SubMap)
TwoKeyMap map_
bool IsKey(const FactoryBase *factory, const std::string &ename) const
Test whether some information about (ename, factory) are stored.
void Delete(const std::string &ename, const FactoryBase *factory)
Delete data that have been retained after the setup phase (using Keep(), AddKeepFlag(),...
static const NoFactory * get()
Class that stores all relevant data for a variable.
std::map< const FactoryBase *, int > request_container
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
Namespace for MueLu classes and methods.
@ Final
Keep data only for this run. Used to keep data useful for Hierarchy::Iterate(). Data will be deleted ...
@ Keep
Always keep data, even accross run. This flag is set by Level::Keep(). This flag is propagated to coa...
@ NextRun
Both UserData and Keep flags force data to be kept and reused for the next run. Do not use MueLu::Nex...
@ UserData
User data are always kept. This flag is set automatically when Level::Set("data", data) is used....
@ Debug
Print additional debugging information.
@ Warnings1
Additional warnings.
short KeepType