introduce new file dumux/common/basicproperties.hh; remove ReferenceElements property from decoupled models; doc

- now every model type tag should be derived from the NumericModel type
tag.
- instead of retrieving the reference elements from the ReferenceElements property,
  use Dune::GenericReferenceElements<Scalar, dim>
- some improvements for the handbook's design patterns and property system chapeters
This commit is contained in:
Andreas Lauser
2010-11-10 10:15:37 +00:00
committed by Andreas Lauser
parent 02ddfea028
commit 96e5522ad5
6 changed files with 379 additions and 238 deletions

View File

@@ -2,7 +2,7 @@
\newcommand{\nextline}{\par\phantom{a}\vspace*{0.1\textwidth}} \newcommand{\nextline}{\par\phantom{a}\vspace*{0.1\textwidth}}
\chapter{The flow of things in \Dumux} \chapter{The flow of things in \Dumux}
This chapter is supposed to show how things are "handed around" in \Dumux. This is not a comprehenisve guide through the modeling framework of \Dumux, but hopefully it will help getting to grips with it. This chapter is supposed to show how things are ``handed around'' in \Dumux. This is not a comprehenisve guide through the modeling framework of \Dumux, but hopefully it will help getting to grips with it.
In Section \ref{content} the structure of \Dumux is shown from a \emph{content} point of view. In Section \ref{content} the structure of \Dumux is shown from a \emph{content} point of view.
Section \ref{implementation} is written from the point of view of the \emph{implementation}. These two approaches are linked by the circled numbers (like \textbf{\textcircled{\ref{init}}}) in the flowchart of Section \ref{implementation} corresponding to the enumeration of the list of Section \ref{content}. This is supposed to demonstrate at which point of the program-flow you are content- and implementation-wise. Section \ref{implementation} is written from the point of view of the \emph{implementation}. These two approaches are linked by the circled numbers (like \textbf{\textcircled{\ref{init}}}) in the flowchart of Section \ref{implementation} corresponding to the enumeration of the list of Section \ref{content}. This is supposed to demonstrate at which point of the program-flow you are content- and implementation-wise.
@@ -562,4 +562,4 @@ $\left \lbrace
\end{landscape} \end{landscape}
\normalsize \normalsize

View File

@@ -1,8 +1,8 @@
\chapter{Tips \& Tricks} \chapter{Tips \& Tricks}
This chapter tries to be a useful collection of tips and tricks that can be handy when working with This chapter tries to be a useful collection of tips and tricks that can be handy when working with
\Dumux. One of the most prominent ideas for developing DUNE/\Dumux is that reinventing the wheel in terms of FEM-code should \Dumux. One of the most prominent ideas for developing DUNE/\Dumux is that reinventing the wheel in terms of FEM-code should
be avoided. We try to follow this idea also in the day-to-day work by stating the \emph{tell us dogma}: "If you found something useful, be avoided. We try to follow this idea also in the day-to-day work by stating the \emph{tell us dogma}: ``If you found something useful,
handy or for other reasons helping when working with \Dumux: put it into this chapter." (or at least write it to the mailing list \\ \verb+dumux@iws.uni-stuttgart.de so somebody else can+). handy or for other reasons helping when working with \Dumux: put it into this chapter.'' (or at least write it to the mailing list \\ \verb+dumux@iws.uni-stuttgart.de so somebody else can+).
\begin{itemize} \begin{itemize}
\item Using the \Dumux-Eclipse profile: \item Using the \Dumux-Eclipse profile:
@@ -11,7 +11,7 @@ Everybody using the same profile has the advantage of resulting in less conflic
\item in eclipse open: \verb#window->preferences->C/C++->Code Style# \item in eclipse open: \verb#window->preferences->C/C++->Code Style#
\item press the \verb+Import+ button \item press the \verb+Import+ button
\item choose the file \verb+eclipse_profile.xml+ from your dumux-devel directory \item choose the file \verb+eclipse_profile.xml+ from your dumux-devel directory
\item make sure that that now DuMux is chosen in "select a profile" \item make sure that that now DuMux is chosen in ``select a profile''
\end{itemize} \end{itemize}
\item Checking whether commit worked: \item Checking whether commit worked:

View File

@@ -21,6 +21,8 @@
\usepackage{rotating} \usepackage{rotating}
\usepackage{subfig} \usepackage{subfig}
%\usepackage{ngerman}
\usepackage[english]{babel}
\DeclareGraphicsExtensions{.eps, .jpg} \DeclareGraphicsExtensions{.eps, .jpg}

View File

@@ -34,5 +34,5 @@ of documentation is documented, and it is easier to get rid of it systematically
The use of exceptions for error handling is encouraged. Until further notice, all exceptions thrown are DuneEx. The use of exceptions for error handling is encouraged. Until further notice, all exceptions thrown are DuneEx.
\item Debugging Code: \item Debugging Code:
Global debugging code is switched off by setting the symbol NDEBUG. In particular, all asserts are Global debugging code is switched off by setting the symbol NDEBUG. In particular, all asserts are
automatically removed. Use those asserts freely!" automatically removed. Use those asserts freely!
\end{itemize} \end{itemize}

View File

@@ -1,28 +1,27 @@
\chapter{\Dumux Design Patterns} \chapter{Design Patterns}
\label{chap:DesignPatterns} \label{chap:DesignPatterns}
This chapter tries to give high-level understanding of some of the This chapter tries to give a high-level understanding of some of the
fundamental techniques which are used by \Dumux and the motivation fundamental techniques which are used by \Dune and \Dumux and the
behind these design decisions. It is assumed that the reader already motivation behind these design decisions. It is assumed that the
posseses some basic knowledge in object oriented programming with C++. reader already has basic experience in object oriented programming
with C++.
First, a quick motivation of C++ template programming is given. Then First, a quick motivation of C++ template programming is given. Then
follows an introduction to polymorphism and the opportunities for it follows an introduction to polymorphism and the opportunities for it
opened by the template mechanism. After that, there is a look at some opened by the template mechanism. After that, some drawbacks
drawbacks associated with template programming. One of these drawbacks associated with template programming are discussed, in particular the
-- deep nesting of template parameters -- motivates the \Dumux blow-up of identifier names and proliferation of template arguments
property system which, in this chapter is outlined from the user and some approaches on how to deal with these problems.
perspective. The chapter concludes with a simple example of how to use
the \Dumux property system.
\section{C++ Template Programming} \section{C++ Template Programming}
One of the main features of modern versions of the C++ language is One of the main features of modern versions of the C++ programming
robust support for templates. Templates are a mechanism for code language is robust support for templates. Templates are a mechanism
generation build directly into the compiler. To see the motivation of for code generation build directly into the compiler. For the
templates, consider a linked list of \texttt{double} values which motivation behind templates, consider a linked list of \texttt{double}
could be implemented like this: values which could be implemented like this:
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
struct DoubleList { struct DoubleList {
DoubleList(const double &val, DoubleList *prevNode = 0) DoubleList(const double &val, DoubleList *prevNode = 0)
{ value = val; if (prevNode) prevNode->next = this; }; { value = val; if (prevNode) prevNode->next = this; };
@@ -35,16 +34,16 @@ int main() {
tail = new DoubleList(2.34, tail); tail = new DoubleList(2.34, tail);
tail = new DoubleList(3.56, tail); tail = new DoubleList(3.56, tail);
}; };
\end{verbatim} \end{lstlisting}
But what if a list of strings is also required? The only ``clean'' way But what should be done if a list of strings is also required? The
to achive this without templates would be to copy only ``clean'' way to achive this without templates would be to copy
\texttt{DoubleListNode}, then rename it and change the type of the \texttt{DoubleList}, then rename it and change the type of the
\texttt{value} attribute. It should be clear that this is a very \texttt{value} attribute. It is obvious that this is a very
cumbersome and error-prone process, so recent standards of the C++ cumbersome, error-prone and unproductive process. For this reason,
programming language provide the template mechanism, which is a way recent standards of the C++ programming language specify the template
let the compiler do the tedious work. Using templates, a generic mechanism, which is a way let the compiler do the tedious work. Using
linked list can be implemented like this: templates, a generic linked list can be implemented like this:
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
template <class ValueType> template <class ValueType>
struct List { struct List {
List(const ValueType &val, List *prevNode = 0) List(const ValueType &val, List *prevNode = 0)
@@ -65,18 +64,20 @@ int main() {
tail2 = new StringList(", ", tail2); tail2 = new StringList(", ", tail2);
tail2 = new StringList("World!", tail2); tail2 = new StringList("World!", tail2);
}; };
\end{verbatim} \end{lstlisting}
Compared to code generation approaches using external tools -- which Compared to approaches which use external tools for code generation --
is the approach chosen for example by the FEniCS~\cite{FENICS-HP} which is the approach chosen for example by the
project -- or heavy use of the C preprocessor -- as done for example FEniCS~\cite{FENICS-HP} project -- or heavy (ab)use of the C
within the UG framework~\cite{UG-HP} -- the template approach has preprocessor -- as done for example by the UG framework~\cite{UG-HP}
several advantages: -- templates have several advantages:
\begin{description} \begin{description}
\item[Well Programmable:] Programming errors are directly detected by \item[Well Programmable:] Programming errors are directly detected by
the C++ compiler and compiler messages also yield useful information the C++ compiler. Thus, diagnostic messages from the compiler are
since the actual source code is visible to the developer and not directly useful because the source code which gets compiled is the
obfuscated by macros or code generation. same as the one written by the developer. This is not the case
for code generators and C-preprocessor macros where the actual
statements processed by the compiler are obfuscated.
\item[Easily Debugable:] Programs which use the template mechanism can be \item[Easily Debugable:] Programs which use the template mechanism can be
debugged almost as easily as C++ programs which do not use debugged almost as easily as C++ programs which do not use
templates. This is due to the fact that the debugger always knows templates. This is due to the fact that the debugger always knows
@@ -90,19 +91,19 @@ quasi-standard Boost~\cite{BOOST-HP} libraries.
\section{Polymorphism} \section{Polymorphism}
In object oriented programming, some functionality often makes sense In object oriented programming, some methods often makes sense for all
for all classes in a hierarchy, but what actually needs to be classes in a hierarchy, but what actually needs to be \textit{done}
\textit{done} can differ for each concrete class. This observation can differ for each concrete class. This observation motivates
motivates \textit{polymorphism}. Fundamentally, polymorphism is all \textit{polymorphism}. Fundamentally, polymorphism means all
techniques where a method call results in the processor executing code techniques where a method call results in the processor executing code
which is specific to the type of object for which the method is which is specific to the type of object for which the method is
called\footnote{This is \textit{poly} of polymorphism: There are called\footnote{This is \textit{poly} of polymorphism: There are
multiple ways to achieve the same goal.}. multiple ways to achieve the same goal.}.
In C++, there are two common ways to achieve polymorphism: The In C++, there are two common ways to achieve polymorphism: The
traditional dynamic polymorphism which is not based on template traditional dynamic polymorphism which does not require template
programming, and static polymorphism which is only made possible by programming, and static polymorphism which is made possible by the
template programming. template mechanism.
\subsection*{Dynamic Polymorphism} \subsection*{Dynamic Polymorphism}
@@ -111,28 +112,28 @@ methods are marked with the \texttt{virtual} keyword in the base
class. Internally, the compiler realizes dynamic polymorphism by class. Internally, the compiler realizes dynamic polymorphism by
storing a pointer to a so-called \texttt{vtable} within each object of storing a pointer to a so-called \texttt{vtable} within each object of
polymorphic classes. The \texttt{vtable} itself stores the entry point polymorphic classes. The \texttt{vtable} itself stores the entry point
of each method which is declared virtual. If such a method is called of each method which is declared \texttt{virtual}. If such a method is
on an object, the compiler generates code which retrieves the method's called on an object, the compiler generates code which retrieves the
address from the object's \texttt{vtable} and then calls it. This method's memory address from the object's \texttt{vtable} and then
explains why this mechanism is called \textbf{dynamic} polymorphism: continues execution at this address. This explains why this mechanism
the code which is actually called are dynamically determined at run is called \textbf{dynamic} polymorphism: the code which is actually
time. executed is dynamically determined at run time.
\begin{example} \begin{example}
\label{example:DynPoly} \label{example:DynPoly}
A class called \texttt{Car} could feature the methods A class called \texttt{Car} could feature the methods
\texttt{gasUsage} which by default corrosponds to the current $CO_2$ \texttt{gasUsage}, which by default corrosponds to the current
emission goal of the European Union but can be overwritten by the $CO_2$ emission goal of the European Union but can be changed by
classes representing actual cars. Also, a method called classes representing actual cars. Also, a method called
\texttt{fuelTankSize} makes sense for all cars, but since there is \texttt{fuelTankSize} makes sense for all cars, but since there is
no useful default, its \texttt{vtable} entry is set to $0$ in the no useful default, its \texttt{vtable} entry is set to $0$ in the
base class which tells the compiler that this method must base class. This tells the compiler that it is mandatorily that this
mandatorily be specified by all derived classes. Finally the method method gets defined in derived classes. Finally, the method
\texttt{range} may calculate the expected remaining kilometers the \texttt{range} may calculate the expected remaining kilometers the
car can drive given a fill level of the fuel tank. Since the car can drive given a fill level of the fuel tank. Since the
\texttt{range} method can retrieve information it needs, it does not \texttt{range} method can retrieve information it needs, it does not
need to be polymorphic. need to be polymorphic.
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
// The base class // The base class
class Car class Car
{public: {public:
@@ -143,10 +144,11 @@ class Car
double range(double fuelTankFillLevel) double range(double fuelTankFillLevel)
{ return 100*fuelTankFillLevel*fuelTankSize()/gasUsage(); } { return 100*fuelTankFillLevel*fuelTankSize()/gasUsage(); }
}; };
\end{verbatim} \end{lstlisting}
Actual car models can now derived from the base class: \noindent
\begin{verbatim} Actual car models can now be derived from the base class like this:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
// A Mercedes S-class car // A Mercedes S-class car
class S : public Car class S : public Car
{public: {public:
@@ -160,11 +162,12 @@ class Lupo : public Car
virtual double gasUsage() { return 2.99; }; virtual double gasUsage() { return 2.99; };
virtual double fuelTankSize() { return 30.0; }; virtual double fuelTankSize() { return 30.0; };
}; };
\end{verbatim} \end{lstlisting}
The \text{range} method called on the base class yields correct result \noindent
for any car type: Calling the \texttt{range} method yields the correct result for any
\begin{verbatim} kind of car:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
void printMaxRange(Car &car) void printMaxRange(Car &car)
{ std::cout << "Maximum Range: " << car.range(1.00) << "\n"; } { std::cout << "Maximum Range: " << car.range(1.00) << "\n"; }
@@ -179,7 +182,7 @@ int main()
std::cout << "Median range: " << s.range(0.50) << "\n"; std::cout << "Median range: " << s.range(0.50) << "\n";
printMaxRange(s); printMaxRange(s);
} }
\end{verbatim} \end{lstlisting}
For both types of cars, \texttt{Lupo} and \texttt{S} the For both types of cars, \texttt{Lupo} and \texttt{S} the
\texttt{printMaxRange} function works as expected, yielding \texttt{printMaxRange} function works as expected, yielding
@@ -201,32 +204,35 @@ What happens if \dots
\subsection*{Static Polymorphism} \subsection*{Static Polymorphism}
Dynamic polymorphism has a few disadvantages, probably the most Dynamic polymorphism has a few disadvantages. The most relevant in the
relevant in the context of \Dumux is that the compiler can not see context of \Dumux is that the compiler can not see ``inside'' the
``inside'' the called methods and thus cannot properly optimize. For called methods and thus cannot optimize properly. For example, modern
example modern C++ compilers 'inline' short methods, i.e. they copy C++ compilers 'inline' short methods, i.e. they copy the method's body
the body the method's body to where it is called. This allows to save to where it is called. First, inlining allows to save a few
a few instructions as well as enables further optimizations which may instructions by avoiding to jump into and out of the method. Second,
depend on specific properties of the function arguments (e.g. constant and probably more importantly, inlining also allows further
value elimination, etc). Inlining and other cross-method optimizations optimizations which depend on specific properties of the function
are next to impossible when using dynamic polymorphism, since these arguments (e.g. constant value elimination) or the contents of the
techniques need to be done by the compiler (i.e. at compile time) function body (e.g. loop unrolling). Unfortunately, inlining and other
while, for virtual methods, the actual code that gets executed is cross-method optimizations are made next to impossible by dynamic
determined at run time. To overcome this issue, template programming polymorphism. This is because these techniques are be done by the
can be used to achive polymorphism at compile time. This works by compiler (i.e. at compile time) whilst, the code which actually gets
supplying the type of the derived class as an additional template executed is only determined at run time for \texttt{virtual}
parameter to the base class. Whenever the base class needs to call methods. To overcome this issue, template programming can be used to
back the derived class, the \texttt{this} pointer of the base class is achive polymorphism at compile time. This works by supplying the type
reinterpreted as a derived object and the method is then called. This of the derived class as an additional template parameter to the base
scheme gives the C++ compiler complete transparency of the code class. Whenever the base class needs to call back the derived class,
executed and thus opens much better optimization oportunities. Since the \texttt{this} pointer of the base class is reinterpreted as a
this mechanism completely happens at compile time, it is called being a pointer to an object of the derived class and the method is
``static polymorphism'' because the called method cannot be changed then called on the reinterpreted pointer. This scheme gives the C++
dynamically at runtime. compiler complete transparency of the code executed and thus opens
much better optimization oportunities. Since this mechanism completely
happens at compile time, it is called ``static polymorphism'' because
the called method cannot be dynamically changed at runtime.
\begin{example} \begin{example}
Using static polymorphism, the base class of example \ref{example:DynPoly} Using static polymorphism, the base class of example \ref{example:DynPoly}
can be written as can be implemented like:
\begin{verbatim} \begin{lstlisting}[name=staticcars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
// The base class. The 'Imp' template parameter is the // The base class. The 'Imp' template parameter is the
// type of the implementation, i.e. the derived class // type of the implementation, i.e. the derived class
template <class Imp> template <class Imp>
@@ -244,11 +250,10 @@ protected:
// reinterpret 'this' as a pointer to an object of type 'Imp' // reinterpret 'this' as a pointer to an object of type 'Imp'
Imp &asImp_() { return *static_cast<Imp*>(this); } Imp &asImp_() { return *static_cast<Imp*>(this); }
}; };
\end{verbatim} \end{lstlisting}
(Note the \texttt{asImp\_()} calls in the \texttt{range} method.) (Notice the \texttt{asImp\_()} calls in the \texttt{range} method.) The
derived classes may now be defined like this:
The derived classes can now be defined like this \begin{lstlisting}[name=staticcars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
\begin{verbatim}
// A Mercedes S-class car // A Mercedes S-class car
class S : public Car<S> class S : public Car<S>
{public: {public:
@@ -262,12 +267,13 @@ class Lupo : public Car<Lupo>
double gasUsage() { return 2.99; }; double gasUsage() { return 2.99; };
double fuelTankSize() { return 30.0; }; double fuelTankSize() { return 30.0; };
}; };
\end{verbatim} \end{lstlisting}
\end{example} \end{example}
Analogously to example \ref{example:DynPoly}, the two kinds of cars \noindent
can be used generically within (template) functions: Analogous to example \ref{example:DynPoly}, the two kinds of cars can
\begin{verbatim} be used generically within (template) functions:
\begin{lstlisting}[name=staticcars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
template <class CarType> template <class CarType>
void printMaxRange(CarType &car) void printMaxRange(CarType &car)
{ std::cout << "Maximum Range: " << car.range(1.00) << "\n"; } { std::cout << "Maximum Range: " << car.range(1.00) << "\n"; }
@@ -284,24 +290,24 @@ int main()
printMaxRange(s); printMaxRange(s);
return 0; return 0;
} }
\end{verbatim} \end{lstlisting}
\textbf{TODO: Exercise} %\textbf{TODO: Exercise}
\section{Common Template Programming Related Problems} \section{Common Template Programming Related Problems}
Although C++ template programming opens a few intriguing Although C++ template programming opens a few intriguing
possibilities, it also has a few disadvantages. In this section a few possibilities, it also has a few disadvantages. In this section a few
of those are outlined and some hints how they can be dealt with are of those are outlined and some hints on how they can be dealt with are
provided. provided.
\subsection*{Blow-Up of Identifiers} \subsection*{Identifier-Name Blow-Up}
One particular problem with advanced use of templates is that the full One particular problem with advanced use of C++ templates is that the
identifier names for types and methods quickly become really long and canonical identifier names for types and methods quickly become really
unreadable. For example a typical line of an error message generated long and unreadable. For example, a typical line of an error message
using GCC 4.5 in conjunction with \Dune-PDELab looks like generated using GCC 4.5 and \Dune-PDELab looks like
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
test_pdelab.cc:171:9: error: no matching function for call to <20>Dune::\ test_pdelab.cc:171:9: error: no matching function for call to <20>Dune::\
PDELab::GridOperatorSpace<Dune::PDELab::PowerGridFunctionSpace<Dune::\ PDELab::GridOperatorSpace<Dune::PDELab::PowerGridFunctionSpace<Dune::\
PDELab::GridFunctionSpace<Dune::GridView<Dune::DefaultLeafGridViewTraits\ PDELab::GridFunctionSpace<Dune::GridView<Dune::DefaultLeafGridViewTraits\
@@ -319,28 +325,29 @@ PDELab::GridFunctionSpaceBlockwiseMapper>, Dumux::PDELab::BoxLocalOperator\
ConstraintsTransformation<long unsigned int, double>, Dune::PDELab::\ ConstraintsTransformation<long unsigned int, double>, Dune::PDELab::\
ConstraintsTransformation<long unsigned int, double>, Dune::PDELab::\ ConstraintsTransformation<long unsigned int, double>, Dune::PDELab::\
ISTLBCRSMatrixBackend<2, 2>, true>::GridOperatorSpace()<29> ISTLBCRSMatrixBackend<2, 2>, true>::GridOperatorSpace()<29>
\end{verbatim} \end{lstlisting}
This seriously complicates diagnostics. Although there is no full This seriously complicates diagnostics. Although there is no full
solution for this problem yet, an effective way of dealing with such solution for this problem yet, an effective way of dealing with such
kinds of error messages is to ignore the type information and to just kinds of error messages is to ignore the type information and to just
go to the location given at the beginning of the line and also go to the location given at the beginning of the line. If nested
consider the error text. If nested templates are used and the given templates are used and the source code at the location seems to be
location looks well, the lines above the actual error specify how correct, the lines printed by the compiler above the actual error
exactly the code was instantiated by the compiler (the lines starting message specify how exactly the code was instantiated (the lines
with \texttt{instantiated from}). In this case it is advisable to look starting with \texttt{instantiated from}). In this case it is
at the innermost location of the code which has been most recently advisable to look at the innermost source code location containing
added. ``new'' source code.
\subsection*{Proliferation of Template Parameters} \subsection*{Proliferation of Template Parameters}
Writing flexible templates often requires a large -- and in some cases Writing flexible templates often requires a large -- and in some cases
even unknown -- number of template parameters. As an example, the type even unknown -- number of template parameters. As an example, the
of the global operator space from \Dune-PDELab which produced the error error message above is produced by the following snipplet:
message above is specified like this: \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
\begin{verbatim} int main()
{
enum {numEq = 2}; enum {numEq = 2};
enum {dim = 2}; enum {dim = 3};
typedef Dune::UGGrid<2> Grid; typedef Dune::UGGrid<dim> Grid;
typedef Grid::LeafGridView GridView; typedef Grid::LeafGridView GridView;
typedef Dune::PDELab::Q1LocalFiniteElementMap<double,double,dim> FEM; typedef Dune::PDELab::Q1LocalFiniteElementMap<double,double,dim> FEM;
typedef TTAG(LensProblem) TypeTag; typedef TTAG(LensProblem) TypeTag;
@@ -369,41 +376,33 @@ message above is specified like this:
> >
GOS; GOS;
GOS gos; // instantiate grid operator space GOS gos; // instantiate grid operator space
\end{verbatim} }
\end{lstlisting}
Although the code above is not really intuitive, it is not a big Although the code above is not really intuitivly readable, this does
problem if the type in case the grid operator space is only required not pose a severe problem as long as the type (in this case the grid
at exactly one location. If, on the other hand, it needs to be operator space) needs to be specified exactly once in the whole
consistend over many locations in the source code, something has to be program. If, on the other hand, it needs to be consistend over
done in order to keep the code maintainable. The next section outlines multiple locations in the source code, measures have to be taken in
approaches on how to tackle this particular problem. order to keep the code maintainable.
\section{The \Dumux Property System} \section{Traits Classes}
\label{sec:propertysystem}
This section is dedicated to means on how to solve the problem of
template argument proliferation. First, a short look on the more
traditional approach using traits classes is taken, then the design of
the \Dumux property system is explained and finally a short example on
how the system can be used is given.
\subsection*{Traits Classes}
A classic approach to reduce the number of template parameters is to A classic approach to reduce the number of template parameters is to
gather the all arguments in a special class, a so-called traits gather the all arguments in a special class, a so-called traits
class. For example instead of writing class. Instead of writing
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
template <class A, class B, class C, class D> template <class A, class B, class C, class D>
class MyClass {}; class MyClass {};
\end{verbatim} \end{lstlisting}
one can use one could use
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
template <class Traits> template <class Traits>
class MyClass {}; class MyClass {};
\end{verbatim} \end{lstlisting}
where the \texttt{Traits} class contains public type definitions for where the \texttt{Traits} class contains public type definitions for
\texttt{A}, \texttt{B}, \texttt{C} and \texttt{D}, e.g. \texttt{A}, \texttt{B}, \texttt{C} and \texttt{D}, e.g.
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
struct MyTraits struct MyTraits
{ {
typedef float A; typedef float A;
@@ -411,44 +410,52 @@ struct MyTraits
typedef short C; typedef short C;
typedef int D; typedef int D;
}; };
\end{verbatim} \end{lstlisting}
\noindent
As there is no a free lunch, the traits approach comes with a few As there is no a free lunch, the traits approach comes with a few
disadvantages of its own: disadvantages of its own:
\begin{enumerate} \begin{enumerate}
\item Trait class hierarchies are problematic. This is due to the fact \item Hierarchies of traits classes are problematic. This is due to
that type defintions must always be defined for the lowest level the fact each level of the hierarchy must be self contained. As a
traits class if it is to be used by higher level classes. result it is impossible to define parameters in the base class which
\item Traits quickly lead to circular dependencies. This implies that depend on parameters which only get specified by a derived traits
types can not be extracted from classes which get the trait class as class.
an argument. \item Traits quickly lead to circular type dependencies. In practice
this means that the traits class can not extract any information
from classes which get the traits class as an argument, even if the
extracted information does not require the traits class.
\end{enumerate} \end{enumerate}
To see the point of the first issue, consider the following example: \noindent
\begin{verbatim} To see the point of the first issue, consider the following:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
struct MyBaseTraits { struct MyBaseTraits {
typedef int Scalar; typedef int Scalar;
typedef std::vector<Scalar> Vector; typedef std::vector<Scalar> Vector;
typedef std::list<Scalar> List;
typedef std::array<Scalar> Array;
typedef std::set<Scalar> Set;
}; };
struct MyDerivedTraits : public MyBaseTraits { struct MyDoubleTraits : public MyBaseTraits {
typedef double Scalar; typedef double Scalar;
}; };
int main() { int main() {
MyDerivedTraits::Vector v{1.41421, 1.73205, 2}; MyDoubleTraits::Vector v{1.41421, 1.73205, 2};
for (int i = 0; i < v.size(); ++i) for (int i = 0; i < v.size(); ++i)
std::cout << v[i]*v[i] << std::endl; std::cout << v[i]*v[i] << std::endl;
} }
\end{verbatim} \end{lstlisting}
Contrary to what is wanted, the \texttt{v} variable is a vector of Contrary to what is intended, the \texttt{v} variable is a vector of
integers. In this case, static polymorphsism does not come to rescue, integers. This problem cannot also be solved using static
since it would lead to a dependency cycle between polymorphism, since it would lead to a dependency cycle between
\texttt{MyBaseTraits} and \texttt{MyDerivedTraits}. \texttt{MyBaseTraits} and \texttt{MyDoubleTraits}.
The second point is illuminated by the following example, where one The second issue is illuminated by the following example, where one
would expect the \texttt{MyTraits::\-VectorType} to be \texttt{std::vector<double>}: would expect the \texttt{MyTraits:: VectorType} to be \texttt{std::vector<double>}:
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
template <class Traits> template <class Traits>
class MyClass { class MyClass {
public: typedef double ScalarType; public: typedef double ScalarType;
@@ -459,18 +466,33 @@ struct MyTraits {
typedef MyClass<MyTraits>::ScalarType ScalarType; typedef MyClass<MyTraits>::ScalarType ScalarType;
typedef std::vector<ScalarType> VectorType typedef std::vector<ScalarType> VectorType
}; };
\end{verbatim} \end{lstlisting}
Although this example seems to be quite pathetic, it is often useful Although this example seems to be quite pathetic, it is often useful
in reality to specify parameters in such a way. in reality to specify parameters in such a way.
\subsection*{Features of the \Dumux Property System}
% TODO: section about separation of functions, parameters and
% independent variables. (e.g. the material laws: BrooksCorey
% (function) (BrooksCoreyParams) function parameters, wetting
% saturation/fluid state (independent variables)
\chapter{The \Dumux Property System}
\label{sec:propertysystem}
This section is dedicated to the of the \Dumux property system. First
a high level overview over its design and principle ideas is given,
then follows a short reference and finally a short example on how the
system can be used is given.
\section{Concepts and Features of the \Dumux Property System}
To get around the issues with traits classes, the \Dumux property To get around the issues with traits classes, the \Dumux property
system was designed. It can be seen as a traits system which allows system was designed. It can be seen as a traits system which allows
easy type inheritance and any acyclic dependency of types. The scope easy type inheritance and any acyclic dependency of types. The scope
at which the property system is executed is completely compile at which the property system is executed is completely compile
time. It is based on the following concepts: time. It is based on the following concepts:
\begin{itemize} \begin{description}
\item[Property:] In the context of the \Dumux property system, a \item[Property:] In the context of the \Dumux property system, a
property is an arbitrary class body which may contain type property is an arbitrary class body which may contain type
definitions, values and methods. Each property has a so-called definitions, values and methods. Each property has a so-called
@@ -479,96 +501,209 @@ time. It is based on the following concepts:
hierarchies, just like normal classes. Each in the context of the hierarchies, just like normal classes. Each in the context of the
\Dumux property system the nodes in the inhertitance hierarchy on \Dumux property system the nodes in the inhertitance hierarchy on
which the property is defined are called \textbf{type tags}. which the property is defined are called \textbf{type tags}.
\item[Property Nesting:] The definition of a property can depend on \end{description}
the value of other properties (as long as there are no cyclic
dependencies).
\item[Introspection:] The \Dumux property systems supports
\textbf{diagnostic messages} which can be used to find out how a
certain property was inherited and where it was defined.
\end{itemize}
\subsection*{\Dumux Property System Reference} It also supports \textbf{property nesting}, i.e. the definition of a
property can depend on the value of other properties (as long as there
are no cyclic dependencies) and \textbf{introspection}, i.e. it can
generate diagnostic messages which can be used to find out where a
certain property was defined and how it was inherited.
\section{\Dumux Property System Reference}
All files where the \Dumux property system is utilized should include All files where the \Dumux property system is utilized should include
the header file \texttt{dumux/common/propertysystem.hh}, declaration the header file \texttt{dumux/ \hskip-1ex{}common/
of new type tags and property tags as well as property definitions \hskip-1ex{}propertysystem.hh}. Declaring of type tags and property
must be done inside the namespace \texttt{Dumux::Properties}. tags as well as property definitions must be done inside the namespace
\texttt{Dumux::Properties}.
\subsection*{Defining Type Tags} \subsection*{Defining Type Tags}
New nodes in the type tag hierarchy can be defined using New nodes in the type tag hierarchy can be defined using
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
NEW_TYPE_TAG(NewTypeTagName, INHERITS_FROM(BaseTagName1, BaseTagName2, ...)); NEW_TYPE_TAG(NewTypeTagName, INHERITS_FROM(BaseTagName1, BaseTagName2, ...));
\end{verbatim} \end{lstlisting}
where the \texttt{INHERITS\_FROM} part is optional. To avoid where the \texttt{INHERITS\_FROM} part is optional. To avoid
inconsistencies in the hierarchy, type tags may only be defined inconsistencies in the hierarchy, type tags may only be defined
exactly once in the whole program. exactly once in the whole program.
\subsubsection*{Declaring Property Tags} \noindent
Example:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
namespace Dumux {
namespace Properties {
NEW_TYPE_TAG(MyBaseTypeTag1);
NEW_TYPE_TAG(MyBaseTypeTag2);
NEW_TYPE_TAG(MyDerivedTypeTag, INHERITS_FROM(MyBaseTypeTag1, MyBaseTypeTag2));
}}
\end{lstlisting}
\subsection*{Declaring Property Tags}
New property tags -- i.e. labels for properties -- are be declared New property tags -- i.e. labels for properties -- are be declared
using using
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
NEW_PROP_TAG(NewPropTagName); NEW_PROP_TAG(NewPropTagName);
\end{verbatim} \end{lstlisting}
A property tag can be declared arbitrarily often inside a program, in A property tag can be declared arbitrarily often inside a program, in
fact it is recomended that all properties are declared in each file fact it is recomended that all properties are declared in each file
where they are used. where they are used.
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
namespace Dumux {
namespace Properties {
NEW_PROP_TAG(MyPropertyTag);
}}
\end{lstlisting}
\subsubsection*{Defining Properties} \subsection*{Defining Properties}
The actual value of a property on a given node of the type tag The actual value of a property on a given node of the type tag
hierarchy is defined using hierarchy is defined using
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
SET_PROP(TypeTagName, PropertyTagName) SET_PROP(TypeTagName, PropertyTagName)
{ {
// arbitrary body of a struct // arbitrary body of a struct
}; };
\end{verbatim} \end{lstlisting}
For each a program, a property itself can be declared at most once, For each program, a property itself can be declared at most once,
although properties may be overwritten at derived type tags. although properties may be overwritten for derived type tags.
Also, the following convenience macros available to define simple Also, the following convenience macros available to define simple
properties: properties:
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
SET_TYPE_PROP(TypeTagName, PropertyTagName, type); SET_TYPE_PROP(TypeTagName, PropertyTagName, type);
SET_BOOL_PROP(TypeTagName, PropertyTagName, booleanValue); SET_BOOL_PROP(TypeTagName, PropertyTagName, booleanValue);
SET_INT_PROP(TypeTagName, PropertyTagName, integerValue); SET_INT_PROP(TypeTagName, PropertyTagName, integerValue);
SET_SCALAR_PROP(TypeTagName, PropertyTagName, floatingPointValue); SET_SCALAR_PROP(TypeTagName, PropertyTagName, floatingPointValue);
\end{verbatim} \end{lstlisting}
\subsubsection*{Unsetting Properties} \noindent
Example:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
namespace Dumux {
namespace Properties {
NEW_TYPE_TAG(MyTypeTag);
\subsubsection*{Converting Tag Names to Tag Types} NEW_PROP_TAG(MyCustomProperty);
NEW_PROP_TAG(MyType);
For the C++ compiler property and type tags look like ordinary NEW_PROP_TAG(MyBoolValue);
types. Both can thus be used as template or function arguments, NEW_PROP_TAG(MyIntValue);
etc. To convert the name of a property tag or a type tag into the NEW_PROP_TAG(MyScalarValue);
corrosponding type, the macros \texttt{TTAG(TypeTagName)} and
\texttt{PTAG(PropertyTagName)} ought to be used.
\subsubsection*{Retrieving Property Values} SET_PROP(MyTypeTag, MyCustomProperty)
{
static void print() { std::cout << "Hello, World!\n"; }
};
SET_TYPE_PROP(MyTypeTag, MyType, unsigned int);
\begin{verbatim} SET_BOOL_PROP(MyTypeTag, MyBoolValue, true);
SET_INT_PROP(MyTypeTag, MyIntValue, 12345);
SET_SCALAR_PROP(MyTypeTag, MyScalarValue, 12345.67890);
}}
\end{lstlisting}
\subsection*{Un-setting Properties}
Sometimes some inherited properties do not make sense for a certain
node in the type tag hierarchy. These properties can be explicitly
un-set using
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
UNSET_PROP(TypeTagName, PropertyTagName);
\end{lstlisting}
The un-set property can not be set for the same type tag, but of
course derived type tags may set it again.
\noindent
Example:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
namespace Dumux {
namespace Properties {
NEW_TYPE_TAG(BaseTypeTag);
NEW_TYPE_TAG(DerivedTypeTag, INHERITS_FROM(BaseTypeTag));
NEW_PROP_TAG(TestProp);
SET_TYPE_PROP(BaseTypeTag, TestProp, int);
UNSET_PROP(DerivedTypeTag, TestProp);
// trying to access the 'TestProp' property for 'DerivedTypeTag'
// will trigger a compiler error!
}}
\end{lstlisting}
\subsection*{Converting Tag Names to Tag Types}
For the C++ compiler, property and type tags look like ordinary
types. Both can thus be used as template arguments. To convert a
property tag name or a type tag name into the corrosponding type, the
macros \texttt{TTAG(TypeTagName)} and \texttt{PTAG(PropertyTagName)}
ought to be used.
\subsection*{Retrieving Property Values}
The class bodies of a property can be retrieved using
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
GET_PROP(TypeTag, PropertyTag) GET_PROP(TypeTag, PropertyTag)
\end{verbatim} \end{lstlisting}
or using the convenience macros
Convenience macros: \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
\begin{verbatim}
GET_PROP_TYPE(TypeTag, PropertyTag) GET_PROP_TYPE(TypeTag, PropertyTag)
GET_PROP_VALUE(TypeTag, PropertyTag) GET_PROP_VALUE(TypeTag, PropertyTag)
\end{verbatim} \end{lstlisting}
the first macro retrieves the type defined using
\texttt{SET\_TYPE\_PROP} and is equivalent to
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
GET_PROP(TypeTag, PropertyTag)::type
\end{lstlisting}
while the second macro retrieves the value of any property defined
using \texttt{SET\_\{INT,BOOL,SCALAR\}\_PROP} and is equivalent to
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
GET_PROP(TypeTag, PropertyTag)::value
\end{lstlisting}
\subsubsection*{Nesting Property definitions} \noindent
Example:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
template <TypeTag>
class MyClass {
// retrieve the ::value attribute of the 'NumEq' property
enum { numEq = GET_PROP(TypeTag, PTAG(NumEq))::value };
// retrieve the ::value attribute of the 'NumPhases' property using the convenience macro
enum { numPhases = GET_PROP_VALUE(TypeTag, PTAG(NumPhases)) };
\subsection*{A Simple Example} // retrieve the ::type attribute of the 'Scalar' property
typedef typename GET_PROP(TypeTag, PTAG(Scalar))::type Scalar;
// retrieve the ::type attribute of the 'Vector' property using the convenience macro
typedef typename GET_PROP_TYPE(TypeTag, PTAG(Vector)) Vector;
};
\end{lstlisting}
\subsection*{Nesting Property Definitions}
Inside property definitions there is access to all other properties of
the inheritance hierarchy. Inside property class bodies, the type tag
for which the current property is requested is available as the
keyword \texttt{TypeTag}.
Example:
\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
SET_PROP(MyModelTypeTag, Vector)
{
private: typedef typename GET_PROP_TYPE(TypeTag, PTAG(Scalar)) Scalar;
public: typedef std::vector<Scalar> type;
};
\end{lstlisting}
\section{A Self-Contained Example}
As a concrete example, let us consider some kinds of cars: Compact As a concrete example, let us consider some kinds of cars: Compact
cars, sedans, trucks, pickups, military tanks and the Hummer-H1 sports cars, sedans, trucks, pickups, military tanks and the Hummer-H1 sports
utility vehicle. Since all these cars share some characteristics it utility vehicle. Since all these cars share some characteristics, it
makes sense to derive the shared properties from the closest matching makes sense to inherit those from the closest matching car type and
car type and only specify the properties which are different. Thus, an only specify the properties which are different. Thus, an inheritance
inheritance diagram for the car types above might look like in figure diagram for the car types above might look like outlined in figure
\ref{fig:car-hierarchy}. \ref{fig:car-hierarchy}.
\begin{figure}[t] \begin{figure}[t]
@@ -589,8 +724,11 @@ inheritance diagram for the car types above might look like in figure
\end{figure} \end{figure}
Using the \Dumux property system, the inheritance hierarchy can be Using the \Dumux property system, the inheritance hierarchy can be
defined using defined by:
\begin{verbatim} \begin{lstlisting}[name=propsyscars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
#include <dumux/common/propertysystem.hh>
#include <iostream>
namespace Dumux { namespace Dumux {
namespace Properties { namespace Properties {
NEW_TYPE_TAG(CompactCar); NEW_TYPE_TAG(CompactCar);
@@ -599,26 +737,23 @@ NEW_TYPE_TAG(Tank);
NEW_TYPE_TAG(Sedan, INHERITS_FROM(CompactCar)); NEW_TYPE_TAG(Sedan, INHERITS_FROM(CompactCar));
NEW_TYPE_TAG(Pickup, INHERITS_FROM(Sedan, Truck)); NEW_TYPE_TAG(Pickup, INHERITS_FROM(Sedan, Truck));
NEW_TYPE_TAG(HummerH1, INHERITS_FROM(Pickup, Tank)); NEW_TYPE_TAG(HummerH1, INHERITS_FROM(Pickup, Tank));
}} \end{lstlisting}
\end{verbatim}
Figure \ref{fig:car-propertynames} lists a few property names which Figure \ref{fig:car-propertynames} lists a few property names which
make sense for at least one of the nodes of figure make sense for at least one of the nodes of figure
\ref{fig:car-hierarchy}. These property names can be declared as \ref{fig:car-hierarchy}. These property names can be declared as
follows: follows:
\begin{verbatim} \begin{lstlisting}[name=propsyscars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
namespace Dumux {
namespace Properties {
NEW_PROP_TAG(TopSpeed); // [km/h] NEW_PROP_TAG(TopSpeed); // [km/h]
NEW_PROP_TAG(NumSeats); // [] NEW_PROP_TAG(NumSeats); // []
NEW_PROP_TAG(CanonCaliber); // [mm] NEW_PROP_TAG(CanonCaliber); // [mm]
NEW_PROP_TAG(GasUsage); // [l/100km] NEW_PROP_TAG(GasUsage); // [l/100km]
NEW_PROP_TAG(AutomaticTransmission); // true/false NEW_PROP_TAG(AutomaticTransmission); // true/false
NEW_PROP_TAG(Payload); // [t] NEW_PROP_TAG(Payload); // [t]
}} \end{lstlisting}
\end{verbatim}
So far the inheritance hierarchy and the property names are completely \noindent
So far, the inheritance hierarchy and the property names are completely
separate. What is missing is setting some values for the property separate. What is missing is setting some values for the property
names on specific nodes of the inheritance hierarchy. Let us assume names on specific nodes of the inheritance hierarchy. Let us assume
the following: the following:
@@ -641,11 +776,10 @@ the following:
but if in doubt more like a tank. but if in doubt more like a tank.
\end{itemize} \end{itemize}
\noindent
Using the \Dumux property system, these characteristics can be Using the \Dumux property system, these characteristics can be
expressed using expressed using
\begin{verbatim} \begin{lstlisting}[name=propsyscars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
namespace Dumux {
namespace Properties {
SET_INT_PROP(CompactCar, TopSpeed, GET_PROP_VALUE(TypeTag, PTAG(GasUsage)) * 30); SET_INT_PROP(CompactCar, TopSpeed, GET_PROP_VALUE(TypeTag, PTAG(GasUsage)) * 30);
SET_INT_PROP(CompactCar, NumSeats, 5); SET_INT_PROP(CompactCar, NumSeats, 5);
SET_INT_PROP(CompactCar, GasUsage, 4); SET_INT_PROP(CompactCar, GasUsage, 4);
@@ -666,21 +800,21 @@ SET_INT_PROP(Pickup, TopSpeed, 120);
SET_INT_PROP(Pickup, Payload, 5); SET_INT_PROP(Pickup, Payload, 5);
SET_INT_PROP(HummerH1, TopSpeed, GET_PROP_VALUE(TTAG(Pickup), PTAG(TopSpeed))); SET_INT_PROP(HummerH1, TopSpeed, GET_PROP_VALUE(TTAG(Pickup), PTAG(TopSpeed)));
}} \end{lstlisting}
\end{verbatim}
\noindent
At this point, the Hummer-H1 has a $120\;mm$ canon which it inherited At this point, the Hummer-H1 has a $120\;mm$ canon which it inherited
from its military ancestor. It can be removed by from its military ancestor. It can be removed by
\begin{verbatim} \begin{lstlisting}[name=propsyscars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
namespace Dumux {
namespace Properties {
UNSET_PROP(HummerH1, CanonCaliber); UNSET_PROP(HummerH1, CanonCaliber);
}}
\end{verbatim}
}} // close namespaces
\end{lstlisting}
\noindent
Now the hierarchy can be queried and some diagnostic messages can be Now the hierarchy can be queried and some diagnostic messages can be
generated. For example generated. For example
\begin{verbatim} \begin{lstlisting}[name=propsyscars,basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
int main() int main()
{ {
std::cout << "top speed of sedan: " << GET_PROP_VALUE(TTAG(Sedan), PTAG(TopSpeed)) << "\n"; std::cout << "top speed of sedan: " << GET_PROP_VALUE(TTAG(Sedan), PTAG(TopSpeed)) << "\n";
@@ -689,9 +823,9 @@ int main()
std::cout << PROP_DIAGNOSTIC(TTAG(Sedan), PTAG(TopSpeed)); std::cout << PROP_DIAGNOSTIC(TTAG(Sedan), PTAG(TopSpeed));
std::cout << PROP_DIAGNOSTIC(TTAG(HummerH1), PTAG(CanonCaliber)); std::cout << PROP_DIAGNOSTIC(TTAG(HummerH1), PTAG(CanonCaliber));
} }
\end{verbatim} \end{lstlisting}
will yield in the following output: will yield in the following output:
\begin{verbatim} \begin{lstlisting}[basicstyle=\ttfamily\scriptsize,numbers=left,numberstyle=\tiny, numbersep=5pt]
top speed of sedan: 210 top speed of sedan: 210
top speed of truck: 100 top speed of truck: 100
Property 'TopSpeed' for type tag 'Sedan' Property 'TopSpeed' for type tag 'Sedan'
@@ -699,7 +833,7 @@ Property 'TopSpeed' for type tag 'Sedan'
defined at test_propertysystem.cc:90 defined at test_propertysystem.cc:90
Property 'CanonCaliber' for type tag 'HummerH1' Property 'CanonCaliber' for type tag 'HummerH1'
explicitly unset at test_propertysystem.cc:113 explicitly unset at test_propertysystem.cc:113
\end{verbatim} \end{lstlisting}
%%% Local Variables: %%% Local Variables:

View File

@@ -70,7 +70,7 @@ can be retrieved by the \Dumux property system and only depend on this
single type tag. Retrieving them is done between line single type tag. Retrieving them is done between line
\ref{tutorial-coupled:retrieve-types-begin} and \ref{tutorial-coupled:retrieve-types-begin} and
\ref{tutorial-coupled:retrieve-types-end}. For an introduction to the \ref{tutorial-coupled:retrieve-types-end}. For an introduction to the
property system, see section \ref{sec:propertysytem}. property system, see section \ref{sec:propertysystem}.
The first thing which should be done at run time is to initialize the The first thing which should be done at run time is to initialize the
message passing interface using DUNE's \texttt{MPIHelper} class. Line message passing interface using DUNE's \texttt{MPIHelper} class. Line
@@ -412,3 +412,8 @@ Use benzene as a new fluid and run the model of Exercise 2 with water
and benzene. Benzene has a density of $889.51 \, \text{kg} / \text{m}^3$ and benzene. Benzene has a density of $889.51 \, \text{kg} / \text{m}^3$
and a viscosity of $0.00112 \, \text{Pa} \; \text{s}$. and a viscosity of $0.00112 \, \text{Pa} \; \text{s}$.
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "dumux-handbook"
%%% End: