Skip to content
Snippets Groups Projects
Commit 370d6be5 authored by Timo Koch's avatar Timo Koch
Browse files

Merge branch 'feature/update-properts-slides' into 'master'

[properties][slides] Renew properties slides

See merge request !270
parents 352310ed bd66a3a3
No related branches found
No related tags found
1 merge request!270[properties][slides] Renew properties slides
Pipeline #47222 passed
---
title: The DuMuX property system
subtitle: Flexible compile-time parameters
subtitle: Flexible compile-time customization
---
# Parameters vs. properties
# Property System Design
## Goals
## Parameters vs. properties
- Change parts of the simulation
- e.g. add a energy equation
- Reuse specializations efficiently
- e.g. test various discretization schemes for same application
- Group properties of the simulation
- Improves readability
- Efficiency (runtime and implementation time)
- <span style="color:#3498DB">Parameters</span> are set at __run-time__
<p>A default value may be used if the user does not provide one at run-time</p>
- <span style="color:#3498DB">Properties</span> are known and set at __compile-time__
<p>
Can be used e.g. as template parameters (__types__ or values with `constexpr` specifier);
No run-time penalty, enable compiler to optimize
</p>
## Customization points
- Simulations have many possible customization points!
- fluid system, constitutive relations
- the type of the grid (incl. dimension)
- the terms in the equation
- discretization scheme
- details of the discretization scheme
- ...
## Challenges
- Simulations have many possible customization points
- This means many properties
- Composing and reusing properties while keeping flexibility is technically challenging
# A C++ solution
## Template parameters
- C++ supports _generic programming_ via __templates__
- e.g. classes defined in terms of other types
- concrete versions of templates are stamped out upon compilation
- e.g. classes parameterized in terms of other types
- concrete versions of templates are defined by specifying concrete types
- the actual type has to be known at compilation time
- __Flexible__: implementation not restricted to _concrete types_
- __Efficient__: decisions made at compile-time
......@@ -33,20 +50,12 @@ An example - `std::vector`
template<typename T, typename A = std::allocator<T>>
class vector;
// Instantiation of a concrete vector - a vector of ints.
// The compiler will define this concrete type for us,
// using the definition of the class template.
std::vector<int> v;
```
## Template parameters
An example - `std::vector`
<img src="./img/template_example.png" width="800"/>
## Template specializations
Template implementations can be specialized for concrete types
......@@ -65,7 +74,23 @@ class MyVector<int>
};
```
## Too many template parameters
## Templates in algorithms
Using class templates, we can write _generic_ algorithms
```cpp
template<typename T>
double two_norm(const MyVector<T>& v)
{
double norm = 0.0;
for (int i = 0; i < v.size(); ++i)
norm += v[i]*v[i];
return std::sqrt(norm);
}
```
## Challenge: Too many parameters
For some classes, providing all template parameters can be very cumbersome and error-prone.
......@@ -77,46 +102,30 @@ using GOF0 = Dune::GridOperator<
CF, CF
>;
DGGO2 dggo2(gfs, cd, gfs, cf, lop, mbe);
```
## Traits classes
## Technique 1: Traits classes
A usual way to group template parameters
```cpp
struct MyGridOperatorTraits
{
using FromGFS = ...;
// ...
};
using GOF0 = Dune::PDELab::GridOperator<MyGridOperatorTraits>;
```
## Inheriting from traits classes
Inheritance may lead to unexpected results
```cpp
struct MyBaseTraits
{
using Scalar = int;
using Vector = std::vector<Scalar>;
};
struct MyDoubleTraits : public MyBaseTraits
template<class PV, class FSY, class FST, class SSY,...>
struct TwoPVolumeVariablesTraits
{
using Scalar = double;
using PrimaryVariables = PV;
using FluidSystem = FSY;
using FluidState = FST;
using SolidSystem = SSY;
using SolidState = SST;
using PermeabilityType = PT;
using ModelTraits = MT;
using SaturationReconstruction = SR;
};
// this is a vector of ints!
typename MyDoubleTraits::Vector v{1.14142, 1.73205};
```
## Type traits
## Technique 2: Type traits
Based on template specialization
Why do we need the type?
```cpp
// Type trait template declaration
......@@ -131,34 +140,47 @@ template<typename T, int size>
struct ValueType<Dune::FieldVector<T, size>> { using type = T; };
```
## Technique 2: Type traits
```cpp
template <class Traits>
class TwoPVolumeVariables
## Type traits
{
...
using FluidSystem = typename Traits::FluidSystem
...
A usage example
```
Usage: these VolumeVariables will work for various FluidSystems:
```cpp
// expecting Container to export value_type
template<typename Container>
void someFunction(const Container& c) {
using V = typename Container::value_type;
// do something with V
// ...
}
Scalar mu = FluidSystem::viscosity(fluidState, paramCache, phaseIdx);
```
## Challenge: Inheritance
Inheritance may lead to unexpected results
```cpp
// using type traits
template<typename Container>
void someFunction(const Container& c) {
using V = typename ValueType<Container>::type;
// do something with V
// ...
}
struct MyBaseTraits
{
using Scalar = int;
using Vector = std::vector<Scalar>;
};
struct MyDoubleTraits : public MyBaseTraits
{
using Scalar = double;
};
// this is a vector of ints!
typename MyDoubleTraits::Vector v{1.14142, 1.73205};
```
# The DuMuX Property System
## Property System Design
- Based on __C++ template specialization__ (_type traits_)
......@@ -194,7 +216,7 @@ A simplified example to illustrate the idea
```cpp
template<class TypeTag>
class GenericClass
class GenericClass // e.g. LocalResidual
{
using PropA = typename Properties::PropTagA<TypeTag>::type;
using PropB = typename Properties::PropTagB<TypeTag>::type;
......@@ -236,8 +258,8 @@ struct Scalar<TypeTag, TTag::BaseTag> { using type = int; };
// specialization of the Vector property for BaseTag
template<class TypeTag>
struct Vector<TypeTag, TTag::BaseTag> {
private: using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public: using type = std::vector<Scalar>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using type = std::vector<Scalar>;
};
```
......@@ -413,3 +435,64 @@ class Problem
* e.g. <span style="color:blue">TwoP, TwoPTwoC, TwoPNI</span>
- By deriving your __type tag__ from those, your problem inherits all type information needed to set up the model at compile time!
- Example: see Exercise
# Alternatives to properties
## Should I create new properties
- Not necessary for most problems
- Only when designing a complex class of models (e.g. porous medium flow models)
- When there is many customization points
## Alternative 1:
- Use a simple template argument
```cpp
template <bool useNeummanBoundaryConditions>
class Problem
{
...
if constexpr (useNeummanBoundaryConditions)
...
else
...
};
```
## Alternative 2:
C++ type traits
```cpp
template<class CouplingManager>
struct SupportsMultithreadedAssembly
: public std::false_type {}
```
## Alternative 2:
C++ type traits
```cpp
class MyCouplingManager { ... };
template<>
struct SupportsMultithreadedAssembly<MyCouplingManager>
: public std::true_type {}
```
## Alternative 2:
Generic algorithm
```cpp
template<class CouplingManager>
class Assembler {
void assemble() {
if (SupportsMultithreadedAssembly<CouplingManager>::value)
// assembly multi-threaded
else
// assembly single-threaded
}
};
```
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment