mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-12-23 16:00:01 -06:00
253 lines
7.8 KiB
TeX
253 lines
7.8 KiB
TeX
\chapter{The \Dumux Property System}
|
|
\label{sec:propertysytem}
|
|
|
|
This chapter tries to give high-level understanding of the motivation
|
|
for the \Dumux property system and how to use it. First, an
|
|
introduction to polymorphism is given. After this, the fundamental
|
|
motivation and the ideas behind the \Dumux property system are
|
|
highlighted and the implementation is outlined from a high-level
|
|
perspective. The chapter concludes with a simple example of how to use
|
|
the \Dumux property system.
|
|
|
|
\section{Polymorphism}
|
|
|
|
In object oriented programming, it often happens that some
|
|
functionality make sense for all classes in a hierarchy, but what
|
|
actually need to be \textit{done} can be quite different. This
|
|
observation gives rise to \textit{polymorphism}. In polymorphism, a
|
|
call to an object's method \textit{means} the same thing, but how this
|
|
method is \textit{implemented} is case specific\footnote{This
|
|
\textit{poly} of polymorphism: There are multiple ways to achieve
|
|
the same goal.}.
|
|
|
|
In C++, there are two common approaches to polymorphism: The
|
|
traditional -- i.e. non-template programming -- dynamic polymorphism,
|
|
and static polymorphism which is made possible by template
|
|
programming.
|
|
|
|
\subsection*{Dynamic Polymorphism}
|
|
|
|
To utilize \textit{dynamic polymorphism} in C++, the polymorphic
|
|
methods are marked with the \texttt{virtual} keyword in the base
|
|
class. Internally, the compiler realizes dynamic polymorphism by
|
|
storing a pointer to a so-called \texttt{vtable} within each object of
|
|
polymorphic classes. The \texttt{vtable} itself stores the entry point
|
|
of each method which is declared virtual. If such a method is called
|
|
on an object, the compiler generates code which retrieves the method's
|
|
address from the object's \texttt{vtable} and then calls it. This
|
|
explains why this mechanism is called \textbf{dynamic} polymorphism:
|
|
the methods which are actually called are dynamically determined at
|
|
run time.
|
|
|
|
\begin{example}
|
|
A class called \texttt{Car} could feature the methods
|
|
\texttt{gasUsage} which by default corrosponds to the current $CO_2$
|
|
emission goal of the European Union but can be overwritten by the
|
|
classes representing actual cars. Also, a method called
|
|
\texttt{fuelTankSize} makes sense for all cars, but since there is
|
|
no useful default, its \texttt{vtable} entry is set to $0$ in the
|
|
base class which tells the compiler that this method must
|
|
mandatorily be specified by all derived classes. Finally the method
|
|
\texttt{range} may calculate the expected remaining kilometers 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
|
|
need to be polymorphic.
|
|
\begin{verbatim}
|
|
// the base class
|
|
class Car
|
|
{public:
|
|
virtual double gasUsage()
|
|
{ return 4.5; };
|
|
virtual double fuelTankSize() = 0;
|
|
|
|
double range(double fuelTankFillLevel)
|
|
{ return 100*fuelTankFillLevel*fuelTankSize()/gasUsage(); }
|
|
}
|
|
\end{verbatim}
|
|
|
|
Actual car models can now derived from the base class:
|
|
\begin{verbatim}
|
|
// a Mercedes S-class car
|
|
class S : public Car
|
|
{public:
|
|
virtual double gasUsage() { return 9.0; };
|
|
virtual double fuelTankSize() { return 65.0; };
|
|
}
|
|
|
|
// A VW Lupo
|
|
class Lupo : public Car
|
|
{public:
|
|
virtual double gasUsage() { return 2.99; };
|
|
virtual double fuelTankSize() { return 30.0; };
|
|
}
|
|
\end{verbatim}
|
|
|
|
The \text{range} method called on the base class yields correct result
|
|
for any car type:
|
|
\begin{verbatim}
|
|
void printMaxRange(Car &car)
|
|
{ std::cout << "Maximum Range: " << car.range(1.00) << "\n"; }
|
|
|
|
int main()
|
|
{
|
|
Lupo lupo;
|
|
S s;
|
|
std::cout << "VW Lupo:"
|
|
std::cout << "Median range: " << lupo.range(0.50) << "\n";
|
|
printMaxRange(lupo);
|
|
std::cout << "Mercedes S-Class:"
|
|
std::cout << "Median range: " << s.range(0.50) << "\n";
|
|
printMaxRange(s);
|
|
return 0;
|
|
}
|
|
\end{verbatim}
|
|
|
|
For both types of cars, \texttt{Lupo} and \texttt{S} the
|
|
\texttt{printMaxRange} function works as expected, yielding
|
|
$1003.3\;\mathrm{km}$ for the Lupo and $722.2\;\mathrm{km}$ for the
|
|
S-Class.
|
|
\end{example}
|
|
|
|
\begin{exc}
|
|
What happens if \dots
|
|
\begin{itemize}
|
|
\item \dots the \texttt{gasUsage} method is removed from the \texttt{Lupo} class?
|
|
\item \dots the \texttt{virtual} qualifier is removed in front of the
|
|
\texttt{gasUsage} method in the base class?
|
|
\item \dots the \texttt{fuelTankSize} method is removed from the \texttt{Lupo} class?
|
|
\item \dots the \texttt{range} method in the \texttt{S} class is
|
|
overwritten?
|
|
\end{itemize}
|
|
\end{exc}
|
|
|
|
\subsection*{Static Polymorphism}
|
|
|
|
|
|
|
|
|
|
% can be written by specifying types as
|
|
% template parameters
|
|
% \item For complex software, the number of template arguments can get
|
|
% quite large
|
|
% \item If an additional template argument is required for a base
|
|
% class template, all derived classes must also be adapted
|
|
% \end{itemize}
|
|
% \end{frame}
|
|
|
|
% \begin{frame}
|
|
% \frametitle{Dynamic Polymorphism}
|
|
|
|
% If a class wants to make a callback to a derived class, the
|
|
% repective method can be declared {\tt virtual}. This has drawbacks:
|
|
% \begin{itemize}
|
|
% \item Overhead due to indirect function call
|
|
% \item No way for the compiler to inline the method
|
|
% \end{itemize}
|
|
% \end{frame}
|
|
|
|
% \begin{frame}[fragile]
|
|
% \frametitle{Static Polymorphism}
|
|
|
|
% Static polymorphism can be used if the type of the derived class is
|
|
% known at compile time:
|
|
% \begin{itemize}
|
|
% \item Additional template parameter {\tt Implementation} for the base class:
|
|
% {\scriptsize
|
|
% \begin{verbatim}
|
|
% template <class Implementation>
|
|
% class Base;
|
|
% \end{verbatim}
|
|
% }
|
|
% \item A static cast to {\tt Implementation} is done before each call-back:
|
|
% {\scriptsize
|
|
% \begin{verbatim}
|
|
% static_cast<Implementation*>(this)->callToImplementation();
|
|
% \end{verbatim}
|
|
% }
|
|
% \item Derived classes are specified like this:
|
|
% {\scriptsize
|
|
% \begin{verbatim}
|
|
% class Derived : public Base<Derived> {};
|
|
% \end{verbatim}
|
|
% }
|
|
% \end{itemize}
|
|
|
|
% \end{frame}
|
|
|
|
% \begin{frame}[fragile]
|
|
% \frametitle{Nested template arguments}
|
|
|
|
% One problem of static Polymorphism:
|
|
% \begin{itemize}
|
|
% \item Template arguments often also require template parameters
|
|
% \item ``Implementation'' arguments are especially nasty:
|
|
% \begin{itemize}
|
|
% \item Assume a base class Base<A, B, Imp>
|
|
% \item Assume a class Derived<B> and that A is C< Derived<B> >
|
|
% \item To specify Derived:
|
|
% \end{itemize}
|
|
% \end{itemize}
|
|
% {\scriptsize
|
|
% \begin{verbatim}
|
|
% template <class B>
|
|
% class Derived : public Base< C<Derived<B> >, B, Derived<B> >
|
|
% \end{verbatim}
|
|
% }
|
|
% \end{frame}
|
|
|
|
% \begin{frame}[fragile]
|
|
% \frametitle{A real-world example}
|
|
|
|
% {\scriptsize
|
|
% \begin{verbatim}
|
|
% template<class ProblemT, class BoxTraitsT, class TwoPTwoCTraitsT>
|
|
% class TwoPTwoCBoxJacobian
|
|
% : public TwoPTwoCBoxJacobianBase<
|
|
% ProblemT,
|
|
% BoxTraitsT,
|
|
% TwoPTwoCTraitsT,
|
|
% TwoPTwoCElementData<TwoPTwoCTraitsT,ProblemT>,
|
|
% TwoPTwoCVertexData<TwoPTwoCTraitsT,ProblemT>,
|
|
% TwoPTwoCFluxData<TwoPTwoCTraitsT,
|
|
% ProblemT,
|
|
% TwoPTwoCVertexData<TwoPTwoCTraitsT,
|
|
% ProblemT> >,
|
|
% TwoPTwoCBoxJacobian<ProblemT,
|
|
% BoxTraitsT,
|
|
% TwoPTwoCTraitsT> >
|
|
% {
|
|
% // ...
|
|
% }
|
|
% \end{verbatim}
|
|
% }
|
|
% \end{frame}
|
|
|
|
% \begin{frame}[fragile]
|
|
% \frametitle{Traits}
|
|
|
|
% A possible solution is to specify a class which specifies the
|
|
% template parameters as type definitions (often called a Traits
|
|
% class): {\scriptsize
|
|
% \begin{verbatim}
|
|
% class Traits
|
|
% { public:
|
|
% typedef int A;
|
|
% typedef C<A> B;
|
|
% };
|
|
|
|
% template <class Traits, class Implementation>
|
|
% class Base {};
|
|
|
|
% template <class Traits>
|
|
% class Derived : public class Base<Traits, Derived<Traits>
|
|
% {};
|
|
% \end{verbatim}
|
|
% }
|
|
|
|
|
|
|
|
%%% Local Variables:
|
|
%%% mode: latex
|
|
%%% TeX-master: "dumux-handbook"
|
|
%%% End:
|