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