MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_Level.hpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// MueLu: A package for multigrid based preconditioning
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact
39// Jonathan Hu (jhu@sandia.gov)
40// Andrey Prokopenko (aprokop@sandia.gov)
41// Ray Tuminaro (rstumin@sandia.gov)
42//
43// ***********************************************************************
44//
45// @HEADER
46#ifndef MUELU_LEVEL_HPP
47#define MUELU_LEVEL_HPP
48
49#include <algorithm> // for swap
50#include <map> // for _Rb_tree_const_iterator, etc
51#include <ostream> // for basic_ostream, etc
52#include <string> // for char_traits, string, etc
53#include <utility> // for pair
54
55#include <Teuchos_Describable.hpp> // for operator<<
56#include <Teuchos_FancyOStream.hpp> // for FancyOStream
57#include <Teuchos_RCPDecl.hpp> // for RCP
58#include <Teuchos_RCP.hpp> // for RCP::operator->, etc
59#include <Teuchos_TestForException.hpp> // for TEUCHOS_TEST_FOR_EXCEPTION
60
61#include <Xpetra_Map.hpp> // for UnderlyingLib definition
62
64#include "MueLu_Exceptions.hpp" // for RuntimeError
66#include "MueLu_KeepType.hpp"
67#include "MueLu_NoFactory.hpp"
68#include "MueLu_Utilities.hpp"
70#include "MueLu_VerbosityLevel.hpp" // for MsgType::Default, VerbLevel
71
72namespace MueLu {
73
99 class Level : public BaseClass {
100
101 public:
103
105
106 Level() : lib_(Xpetra::NotSpecified), levelID_(-1) { }
107
108 Level(RCP<FactoryManagerBase>& factoryManager) : lib_(Xpetra::UseTpetra), levelID_(-1), factoryManager_(factoryManager) { }
109
111 virtual ~Level() { }
112
114
116
118 RCP<Level> Build();
119
121
123
124
126 int GetLevelID() const;
127
129 void SetLevelID(int levelID);
130
132 RCP<Level>& GetPreviousLevel() { return previousLevel_; }
133
136 void SetPreviousLevel(const RCP<Level>& previousLevel);
138
140
141
142 // Users should not use this method.
143 void SetFactoryManager(const RCP<const FactoryManagerBase>& factoryManager);
144
146 // Users should not use this method
147 const RCP<const FactoryManagerBase> GetFactoryManager();
149
151
152
156 template <class T>
157 void Set(const std::string& ename, const T& entry, const FactoryBase* factory = NoFactory::get()) {
158 const FactoryBase* fac = GetFactory(ename, factory);
159
160 if (fac == NoFactory::get()) {
161 // Any data set with a NoFactory gets UserData keep flag by default
163 }
164
165 // Store entry only if data have been requested (or any keep flag)
166 if (IsRequested(ename, factory) || GetKeepFlag(ename, factory) != 0) {
167 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(factory, ename), Exceptions::RuntimeError, "" + ename + " not found in");
168 map_[factory][ename]->SetData(entry);
169
170 } else {
171 GetOStream(Runtime1) << "Level::Set: Not storing \"" << ename << "\" generated by factory " << factory->ShortClassName() << "["<<factory->GetID()<<"]"
172 << " on level " << toString(GetLevelID()) << ", as it has not been requested and no keep flags were set for it" << std::endl;
173 }
174 } // Set
175
177
180
182
190 template <class T>
191 T& Get(const std::string& ename, const FactoryBase* factory = NoFactory::get()) {
192 const FactoryBase* fac = GetFactory(ename, factory);
193/* printf("(l=%d) getting \"%20s\" generated by %10p [actually, generated by %p (%43s)]\n",
194 levelID_, ename.c_str(), factory, fac, fac->description().c_str());*/
195
196 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(fac, ename), Exceptions::RuntimeError, "\"" + ename + "\" generated by factory \"" + fac->description() + "\" not found on level " + toString(GetLevelID()) + ".");
197
198 if (!IsAvailable(ename, fac)) {
199 TEUCHOS_TEST_FOR_EXCEPTION(NumRequests(fac, ename) < 1 && GetKeepFlag(ename, fac) == 0, Exceptions::RuntimeError,
200 "\"" << ename << "\" has not been requested (counter = " << NumRequests(fac, ename) << ", "
201 "KeepFlag = " << GetKeepFlag(ename, fac) << "). " << std::endl <<
202 "Generating factory:" << *fac << " NoFactory = " << NoFactory::get());
203 fac->CallBuild(*this);
204 Release(*fac);
205 }
206
207 TEUCHOS_TEST_FOR_EXCEPTION(!IsAvailable(ename, fac), Exceptions::RuntimeError,
208 "MueLu::Level::Get(): factory did not produce expected output on level " << GetLevelID()
209 << ". The data \"" << ename << "\" has not been generated by " << *fac);
210
211 return map_[fac][ename]->template GetData<T>();
212 }
213
215 template <class T>
216 void Get(const std::string& ename, T& rValue, const FactoryBase* factory = NoFactory::get()) {
217 rValue = Get<T>(ename, factory);
218 }
219
220 template <class T>
221 bool IsType(const std::string& ename, const FactoryBase* factory = NoFactory::get()) {
222 const FactoryBase* fac = GetFactory(ename, factory);
223
224 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(fac, ename), Exceptions::RuntimeError, "\"" + ename + "\" generated by factory \"" + fac->description() + "\" not found on level " + toString(GetLevelID()) + ".");
225
226 if (!IsAvailable(ename, fac)) {
227 TEUCHOS_TEST_FOR_EXCEPTION(NumRequests(fac, ename) < 1 && GetKeepFlag(ename, fac) == 0, Exceptions::RuntimeError,
228 "\"" << ename << "\" has not been requested (counter = " << NumRequests(fac, ename) << ", "
229 "KeepFlag = " << GetKeepFlag(ename, fac) << "). " << std::endl <<
230 "Generating factory:" << *fac << " NoFactory = " << NoFactory::get());
231 fac->CallBuild(*this);
232 Release(*fac);
233 }
234
235 TEUCHOS_TEST_FOR_EXCEPTION(!IsAvailable(ename, fac), Exceptions::RuntimeError,
236 "MueLu::Level::Get(): factory did not produce expected output on level " << GetLevelID()
237 << ". The data \"" << ename << "\" has not been generated by " << *fac);
238
239 return map_[fac][ename]->template CheckType<T>();
240 }
241
248 std::string GetTypeName(const std::string& ename, const FactoryBase* factory = NoFactory::get()) {
249 const FactoryBase* fac = GetFactory(ename, factory);
250 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(fac, ename), Exceptions::RuntimeError, "\"" + ename + "\" not found");
251
252 TEUCHOS_TEST_FOR_EXCEPTION(!IsAvailable(ename, fac), Exceptions::RuntimeError, "MueLu::Level::GetTypeString(): Data "
253 "\"" << ename << "\" generated by " << *fac << " is not available.");
254
255 return map_[fac][ename]->GetTypeName();
256 }
257
259
261
262
264 // This method is intented to be used by user drivers for printing, debugging or to keep some computed data for a next run of the setup phase.
265 //
266 // This method is an alias for: AddKeepFlag(ename, factory, MueLu::Keep)
267 // See also the description of KeepEnum for more information.
268 //
269 // To undo a keep request, one can use:
270 // - Delete(ename, factory) to delete the data and remove the "Keep" flag
271 // - or RemoveKeepFlag(ename, factory, MueLu::Keep) to go back to previous condition (data are kept only if internal MueLu logic need so).
272 //
273 // Note: Level variables tagged using this methods are also keep on the levels built using this.Build().
274 // This means that is you request to keep a specific variable on a fine level, all the coarser level that are created automatically during the setup phase will also retain the same variable.
275 void Keep(const std::string & ename, const FactoryBase* factory) { AddKeepFlag(ename, factory, MueLu::Keep); } // Note: do not add default value for input parameter 'factory'
276
278 // Special cases:
279 // - If entry (ename, factory) does not exist, nothing is done.
280 // - If entry exists but counter !=, entry cannot be desallocated before counter set to 0 (using Release()) so an exeption is thrown.
281 void Delete(const std::string& ename, const FactoryBase* factory) { // Note: do not add default value for input parameter 'factory'
282 if (!IsKey(factory, ename))
283 return;
284
285 // Precondition:
286 // Delete() should only be called if counter == 0
287 // 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
288 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.");
289 // If counter == 0 and entry exists, this means that a keep flag is set. Or there is an internal logic problem.
290 TEUCHOS_TEST_FOR_EXCEPTION(GetKeepFlag(ename, factory) == 0, Exceptions::RuntimeError, "MueLu::Level::Delete(), Keep flag == 0?");
291
292 RemoveKeepFlag(ename, factory, MueLu::All); // will delete the data if counter == 0
293
294 // Post condition: data must have been deleted
295 TEUCHOS_TEST_FOR_EXCEPTION(IsAvailable(ename, factory) == true, Exceptions::RuntimeError, "MueLu::Level::Delete(): Internal error (Post condition). Data have not been deleted.");
296 }
297
299 void Clear();
300
303 void ExpertClear();
304
308 bool IsKept(const std::string& ename, const FactoryBase* factory, KeepType keep) const { return GetKeepFlag(ename, factory) & keep; }
309
314 void AddKeepFlag(const std::string & ename, const FactoryBase* factory = NoFactory::get(), KeepType keep = MueLu::Keep); // TODO: remove default value for input parameter 'factory'?
315
319 void RemoveKeepFlag(const std::string & ename, const FactoryBase* factory, KeepType keep = MueLu::All);
320
322 KeepType GetKeepFlag(const std::string& ename, const FactoryBase* factory) const;
323
325
328
329
331 void Request(const FactoryBase& factory);
332
334 void Release(const FactoryBase& factory);
335
337 void DeclareInput(const std::string& ename, const FactoryBase* factory, const FactoryBase* requestedBy = NoFactory::get() );
338
340 void DeclareDependencies(const FactoryBase* factory, bool bRequestOnly = false, bool bReleaseOnly = false);
341
343 void Request(const std::string& ename, const FactoryBase* factory = NoFactory::get(), const FactoryBase* requestedBy = NoFactory::get());
344
346 void Release(const std::string& ename, const FactoryBase* factory = NoFactory::get(), const FactoryBase* requestedBy = NoFactory::get());
347
349
351
352
354 bool IsAvailable(const std::string& ename, const FactoryBase* factory = NoFactory::get()) const {
355 if (!IsKey(factory, ename))
356 return false;
357 try {
358 return Get(factory, ename)->IsAvailable();
359 } catch (...) {
360 return false;
361 }
362 }
363
365 bool IsRequested(const std::string& ename, const FactoryBase* factory = NoFactory::get()) const {
366 if (!IsKey(factory, ename))
367 return false;
368 try {
369 return IsRequested(Get(factory, ename));
370 } catch (...) {
371 return false;
372 }
373 }
374
375
377
379
381 std::string description() const;
382
384 // TODO: print only shows requested variables. check if we also list kept factories with ref counter=0?
385 void print(std::ostream& out, const VerbLevel verbLevel = Default) const;
386
387#if defined(HAVE_MUELU_BOOST) && defined(HAVE_MUELU_BOOST_FOR_REAL) && defined(BOOST_VERSION) && (BOOST_VERSION >= 104400)
388 void UpdateGraph(std::map<const FactoryBase*, BoostVertex>& vindices,
389 std::map<std::pair<BoostVertex, BoostVertex>, std::string>& edges,
390 BoostProperties& dp,
391 BoostGraph& graph) const;
392#endif
393
395
398
399 void setlib(Xpetra::UnderlyingLib lib2) { lib_ = lib2; }
400 Xpetra::UnderlyingLib lib() { return lib_; }
401
402 void SetComm(RCP<const Teuchos::Comm<int> > const &comm) { comm_ = comm; }
403 RCP<const Teuchos::Comm<int> > GetComm() const { return comm_; }
404
405 private:
406
408 Level(const Level& source);
409
411 //
412 // If factory == NULL, the default factory is defined as follow:
413 // - If user data is available, it is considered as the default and the factory manager is ignored.
414 // => The default factory is then NoFactory.
415 // - Else, the factory manager is used to get the default factory.
416 //
417 // This strategy allows to use the same factory manager on the fine and coarse level without any trouble.
418 // Example :
419 //
420 // FineLevel:
421 // ----------
422 // A -> User provided
423 // Nullspace -> User provided
424 //
425 // CoarseLevel:
426 // ------------
427 // A -> RAPFactory
428 // NullSpace -> NullspaceFactory
429 //
430 const FactoryBase* GetFactory(const std::string& varname, const FactoryBase* factory) const;
431
433 Xpetra::UnderlyingLib lib_;
434 RCP<const Teuchos::Comm<int> > comm_;
435
436 typedef const FactoryBase* Key1;
437 typedef const std::string Key2;
438 typedef RCP<VariableContainer> Value;
439 typedef Teuchos::map<Key2, Value> SubMap;
440 typedef Teuchos::map<Key1, SubMap> TwoKeyMap;
441
442 int levelID_; // id number associated with level
443 RCP<const FactoryManagerBase> factoryManager_;
444 RCP<Level> previousLevel_; // linked list of Level
446
448
449
451 bool IsKey(const FactoryBase* factory, const std::string& ename) const {
452 TwoKeyMap::const_iterator it = map_.find(factory);
453 return (it != map_.end()) ? (it->second).count(ename) : false;
454 }
455
456 bool IsAvailableFactory(const FactoryBase* factory) const {
457 TwoKeyMap::const_iterator it = map_.find(factory);
458 if (it == map_.end())
459 return false;
460 for (SubMap::const_iterator sit = it->second.begin(); sit != it->second.end(); sit++) {
461 if (sit->second->IsAvailable())
462 return true;
463 }
464 return false;
465 }
466
467 bool IsRequested(const Value& v) const {
468 TEUCHOS_TEST_FOR_EXCEPTION(v->NumAllRequests() == 0 && v->GetKeepFlag() == 0, Exceptions::RuntimeError,
469 "Internal logic error: if counter == 0, the entry in countTable_ should have been deleted");
470 return v->IsRequested();
471 }
472
473 bool IsRequestedBy(const FactoryBase* factory, const std::string& ename, const FactoryBase* requestedBy) const {
474 if (!IsKey(factory, ename))
475 return false;
476
477 return IsRequestedBy(Get(factory, ename), requestedBy);
478 }
479
480 bool IsRequestedBy(const Value& v, const FactoryBase* requestedBy) const {
481 TEUCHOS_TEST_FOR_EXCEPTION(v->NumAllRequests() == 0 && v->GetKeepFlag() == 0, Exceptions::RuntimeError,
482 "Internal logic error: if counter == 0, the entry in countTable_ should have been deleted");
483 return v->IsRequested(requestedBy);
484 }
485
486 bool IsRequestedFactory(const FactoryBase* factory) const {
487 TwoKeyMap::const_iterator it = map_.find(factory);
488 if (it == map_.end())
489 return false;
490 for (SubMap::const_iterator sit = it->second.begin(); sit != it->second.end(); sit++)
491 if (IsRequested(sit->second))
492 return true;
493 return false;
494 }
495
496 const Value& Get(const FactoryBase* factory, const std::string& ename) const {
497 TwoKeyMap::const_iterator it = map_.find(factory);
498 TEUCHOS_TEST_FOR_EXCEPTION(it == map_.end(), Exceptions::RuntimeError, "Key (" << factory << ", *) does not exist.");
499
500 SubMap::const_iterator sit = it->second.find(ename);
501 TEUCHOS_TEST_FOR_EXCEPTION(sit == it->second.end(), Exceptions::RuntimeError, "Key (" << factory << ", " << ename << ") does not exist.");
502
503 return sit->second;
504 }
505
506 int NumRequests(const FactoryBase* factory, const std::string & ename) const {
507 TEUCHOS_TEST_FOR_EXCEPTION(!IsKey(factory, ename), Exceptions::RuntimeError, "\"" + ename + "\" not found. Do a request first.");
508 const Teuchos::RCP<MueLu::VariableContainer>& v = Get(factory, ename);
509 TEUCHOS_TEST_FOR_EXCEPTION(v->NumAllRequests() == 0 && v->GetKeepFlag() == 0, Exceptions::RuntimeError,
510 "NumRequests(): Internal logic error: if counter == 0, the entry in countTable_ should have been deleted");
511 return v->NumAllRequests();
512 }
513
514 int CountRequestedFactory(const FactoryBase* factory) const {
515 TwoKeyMap::const_iterator it = map_.find(factory);
516 if (it == map_.end())
517 return 0;
518
519 int cnt = 0;
520 for (SubMap::const_iterator sit = it->second.begin(); sit != it->second.end(); sit++)
521 cnt += sit->second->NumAllRequests();
522
523 return cnt;
524 }
525
527
528 }; //class Level
529
530} //namespace MueLu
531
532//TODO: Caps should not matter
533
534#endif // MUELU_LEVEL_HPP
Base class for MueLu classes.
virtual std::string description() const
Return a simple one-line description of this object.
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 CallBuild(Level &requestedLevel) const =0
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 SetComm(RCP< const Teuchos::Comm< int > > const &comm)
Teuchos::map< Key2, Value > SubMap
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.
bool IsType(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Xpetra::UnderlyingLib lib_
void Get(const std::string &ename, T &rValue, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access).
Level(const Level &source)
Copy constructor.
void setlib(Xpetra::UnderlyingLib lib2)
bool IsRequestedBy(const Value &v, const FactoryBase *requestedBy) const
RCP< Level > & GetPreviousLevel()
Previous level.
static RequestMode requestMode_
const Value & Get(const FactoryBase *factory, const std::string &ename) const
void Release(const FactoryBase &factory)
Decrement the storage counter for all the inputs of a factory.
int CountRequestedFactory(const FactoryBase *factory) const
const std::string Key2
RCP< const Teuchos::Comm< int > > GetComm() const
const RCP< const FactoryManagerBase > GetFactoryManager()
returns the current factory manager
void SetLevelID(int levelID)
Set level number.
bool IsRequested(const Value &v) const
void print(std::ostream &out, const VerbLevel verbLevel=Default) const
Printing method.
virtual ~Level()
Destructor.
Teuchos::map< Key1, SubMap > TwoKeyMap
Sub-map container (Key2 -> Value).
RCP< VariableContainer > Value
const FactoryBase * Key1
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.
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
RequestMode GetRequestMode() const
RCP< const Teuchos::Comm< int > > comm_
KeepType GetKeepFlag(const std::string &ename, const FactoryBase *factory) const
Get the flag combination set for variable 'ename' generated by 'factory'.
void Set(const std::string &ename, const T &entry, const FactoryBase *factory=NoFactory::get())
RCP< const FactoryManagerBase > factoryManager_
bool IsKept(const std::string &ename, const FactoryBase *factory, KeepType keep) const
bool IsAvailableFactory(const FactoryBase *factory) const
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)
Xpetra::UnderlyingLib lib()
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_
Level(RCP< FactoryManagerBase > &factoryManager)
bool IsKey(const FactoryBase *factory, const std::string &ename) const
Test whether some information about (ename, factory) are stored.
void Keep(const std::string &ename, const FactoryBase *factory)
Request to keep variable 'ename' generated by 'factory' after the setup phase.
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()
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.
@ Keep
Always keep data, even accross run. This flag is set by Level::Keep(). This flag is propagated to coa...
@ UserData
User data are always kept. This flag is set automatically when Level::Set("data", data) is used....
@ Runtime1
Description of what is happening (more verbose).
short KeepType
std::string toString(const T &what)
Little helper function to convert non-string types to strings.