Skip to content
Snippets Groups Projects
properties.md 13 KiB
Newer Older
---
title: The DuMuX property system
subtitle: Flexible compile-time customization
Timo Koch's avatar
Timo Koch committed
# Property System Design
Timo Koch's avatar
Timo Koch committed
- Change parts of the simulation
  - e.g. add a energy equation
- Reuse specializations efficiently
Timo Koch's avatar
Timo Koch committed
  - e.g. test various discretization schemes for same application
- Group properties of the simulation
  - Improves readability
Timo Koch's avatar
Timo Koch committed
- Efficiency (runtime and implementation time)

## 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
## Template parameters

- C++ supports _generic programming_ via __templates__
Timo Koch's avatar
Timo Koch committed
    - 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

## Template parameters

An example - `std::vector`

```cpp
// Declaration of the class template, usable with any
// `T` that fulfills the requirements that `vector` poses on it.
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 specializations

Template implementations can be specialized for concrete types

```cpp
template<typename T>
class MyVector
{
    // Generic implementation for any T
};

template<>
class MyVector<int>
{
    // specialized implementation for `int`
};
```

Timo Koch's avatar
Timo Koch committed
## 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.

```cpp
// Example from dune-pdelab. 9 template parameters!
using GOF0 = Dune::GridOperator<
    GFS, GFS, LOP, MBE,
    RF, RF, RF,
    CF, CF
>;

```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dune-pdelab/doc/Recipes/recipe-operator-splitting.cc`</span>
Timo Koch's avatar
Timo Koch committed
## Technique 1: Traits classes

A usual way to group template parameters

```cpp
template<class PV, class FSY, class FST, class SSY,...>
struct TwoPVolumeVariablesTraits
    using PrimaryVariables = PV;
    using FluidSystem = FSY;
    using FluidState = FST;
    using SolidSystem = SSY;
    using SolidState = SST;
    using PermeabilityType = PT;
    using ModelTraits = MT;
    using SaturationReconstruction = SR;
};
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/dumux/porousmediumflow/2p/model.hh`</span>
Timo Koch's avatar
Timo Koch committed
## Technique 2: Type traits

Why do we need the type?

```cpp
// Type trait template declaration
template<typename T> struct ValueType;

// Specialization for vectors of T
template<typename T, typename Allocator>
struct ValueType<std::vector<T, Allocator>> { using type = T; };

// Specialization for Dune::FieldVector
template<typename T, int size>
struct ValueType<Dune::FieldVector<T, size>> { using type = T; };
```

Timo Koch's avatar
Timo Koch committed
## Technique 2: Type traits

```cpp

template <class Traits>
class TwoPVolumeVariables

   ...
using FluidSystem = typename Traits::FluidSystem
   ...
Timo Koch's avatar
Timo Koch committed

<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/dumux/porousmediumflow/2p/volumevariables.hh`</span>

Usage: these VolumeVariables will work for various FluidSystems:
```cpp
Scalar mu = FluidSystem::viscosity(fluidState, paramCache, phaseIdx);
Timo Koch's avatar
Timo Koch committed
## Challenge: Inheritance

Inheritance may lead to unexpected results

```cpp
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};
Timo Koch's avatar
Timo Koch committed
# The DuMuX Property System
## Property System Design

- Based on __C++ template specialization__ (_type traits_)
- From a __type tag__, one can extract __properties__ defined for it
- A __property tag__ is a type trait declaration (or default implementation)
- A __property__ is exported from a __property tag__ specialization for a __type tag__
- (The property system also supports definitions of traits classes - see later)
## Property System Design
A simplified example to illustrate the idea
// myproperties.hh
namespace Dumux::Properties {
namespace TTag { struct MyTypeTag {}; }

// some property tag
template<typename TypeTag> struct PropTagA;

// property definition for MyTypeTag
template<>
struct PropTagA<MyTypeTag>
{ using type = /*the actual property*/; };
}  // namespace Dumux::Properties
```


## Property System Design

A simplified example to illustrate the idea

```cpp
template<class TypeTag>
Timo Koch's avatar
Timo Koch committed
class GenericClass // e.g. LocalResidual
    using PropA = typename Properties::PropTagA<TypeTag>::type;
    using PropB = typename Properties::PropTagB<TypeTag>::type;
    // ...
    // A property could be, for instance, a fluid system
    using FS = typename Properties::FluidSystem<TypeTag>::type;
};
```


## Property System Design


__Issue__: Inheritance not (easily) possible. All type traits need to be specialized for `MyTypeTag`.

__Goal__: We would like __type tags__ to be composable via inheritance, while providing a mechanism for customizing any property defined in the hierarchy.


## Actual Design

- A hierarchy of nodes -- called __type tags__ -- is defined (via inheritance)
- __Properties__ are defined for the appropriate nodes in this hierarchy.
- The definition of __properties__ may _depend on_ arbitrary other properties, which may be _overwritten_ at any higher node of the hierarchy
- The only requirement for properties is that they may not exhibit __cyclic dependencies__


## Actual Design

Let's implement the `Vector` example using the property system

```cpp
namespace Properties {
namespace TTag { struct BaseTag {}; }

// specialization of the Scalar property for BaseTag
template<class TypeTag>
struct Scalar<TypeTag, TTag::BaseTag> { using type = int; };

// specialization of the Vector property for BaseTag
template<class TypeTag>
struct Vector<TypeTag, TTag::BaseTag> {
Timo Koch's avatar
Timo Koch committed
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
    using type = std::vector<Scalar>;
## Actual Design

Let's implement the `Vector` example using the property system
namespace Properties {
namespace TTag {
struct DoubleTag { using InheritsFrom = std::tuple<BaseTag>; };
}  // namespace TTag

// Specialization of the Scalar property for DoubleTag
template<class TypeTag>
struct Scalar<TypeTag, TTag::DoubleTag>
{ using type = double; };
```

```cpp
// using the property
using Vector = GetPropType<DoubleTag, Properties::Vector>;
Vector v{1.41421, 1.73205};  // v is a std::vector<double>!
```

## Using __type tags__ as traits classes

```cpp
struct BaseTag
{
    using Scalar = double;

    // Important: do not directly use Scalar here as it would
    // break the possibility to overwrite it in a child node
    template<typename TypeTag>
    using Vector = std::vector<
        GetPropType<TypeTag, Properties::Scalar>
    >;
};
```


## The DuMu<sup>x</sup> property system

- Extension $\leftrightarrow$ tree of so called TypeTag nodes
- Each TypeTag is associated with Properties
![](./img/typetag_nodes.png)


## The DuMu<sup>x</sup> property system

- Hierarchy / Inheritance
  - TypeTags can inherit properties from other TypeTags
  - Properties with the same name are overwritten
![](./img/typetag_hierarchy.png)


## How to use I

Creating new  <span style="color:blue">TypeTag</span> nodes

```cpp
namespace Dumux::Properties::TTag {
struct MyTypeTag {};

struct MyOtherTypeTag
{ using InheritsFrom = std::tuple<MyTypeTag>; }

} // end namespace Dumux::Properties::TTag
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux-course/exercises/exercise-properties/properties.hh`</span>

## How to use II

Creating new <span style="color:blue">property tags</span> (empty, unset properties) $\leftrightarrow$ Property names are unique!
```cpp
namespace Dumux::Properties {
Timo Koch's avatar
Timo Koch committed
DUMUX_DEFINE_PROPERTY(Problem)
} // end namespace Dumux::Properties
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/test/common/propertysystem/test_propertysystem_aliases.cc`</span>

Usually not needed in user code because
all necessary properties are already defined in [dumux/common/properties.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/common/properties.hh).
Timo Koch's avatar
Timo Koch committed
Setting **type** properties for a specific type tag `MyTypeTag`

```cpp
namespace Properties {

template<class TypeTag>
struct Problem<TypeTag, TTag::MyTypeTag>
{ using type = Dumux::MyProblem<TypeTag>; };

} // end namespace Properties
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux-course/exercises/exercise-properties/properties.hh`</span>
Timo Koch's avatar
Timo Koch committed
## How to use III (alternative)

Alternatively, using **type** alias properties for a specific type tag `MyTypeTag`

```cpp
namespace Properties::TTag {

struct MyTypeTag {
    ...
    template<class TypeTag>
    using Problem = Dumux::MyProblem<TypeTag>;
Timo Koch's avatar
Timo Koch committed
    ...
};

} // end namespace Properties
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/test/geomechanics/hyperelastic/properties.hh`</span>
Timo Koch's avatar
Timo Koch committed

## How to use IV

Timo Koch's avatar
Timo Koch committed
Setting **value** properties for a specific type tag `MyTypeTag`

```cpp
namespace Properties{

template<class TypeTag>
struct EnableBoxInterfaceSolver<TypeTag, TTag::MyTypeTag>
{ static constexpr bool value = true; }

} // end namespace Properties
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/test/porousmediumflow/2p/boxdfm/properties.hh`</span>
Timo Koch's avatar
Timo Koch committed
## How to use IV (alternative)

Setting **value** for a alias property for a specific type tag `MyTypeTag`

```cpp
namespace Properties {

struct MyTypeTag {
    ...
    using EnableBoxInterfaceSolver = std::true_type;
    ...
};

} // end namespace Properties
```

Timo Koch's avatar
Timo Koch committed
Getting the property type set for a `TypeTag`

```cpp
namespace Dumux{

template <class TypeTag>
class Problem
{
    using Scalar = GetPropType<TypeTag, Properties::Scalar>;

    constexpr auto useIFS = getPropValue<
        TypeTag, Properties::EnableBoxInterfaceSolver
    >();
};

} // end namespace Dumux
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/examples/1ptracer/problem_tracer.hh`</span>

## Summary

- "Top-level" classes in DuMu<sup>x</sup> depend on a __type tag__ and use the property system to obtain other types
- Setting a property for your __type tag__ will affect all classes using the same __type tag__
- Each model defines a set of properties grouped in a __type tag__
  * 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
Timo Koch's avatar
Timo Koch committed

# 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 enableRegularization = isRegularized()>
Scalar pcgw(const Scalar sw, const Scalar /*dummySn*/) const
Timo Koch's avatar
Timo Koch committed
{
    ...
    if constexpr (enableRegularization)^
    {
Timo Koch's avatar
Timo Koch committed
        ...
Timo Koch's avatar
Timo Koch committed
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/dumux/material/fluidmatrixinteractions/3p/parkervangenuchten.hh`</span>
Timo Koch's avatar
Timo Koch committed

## Alternative 2:

C++ type traits

```cpp
template<class CouplingManager>
struct SupportsMultithreadedAssembly
: public std::false_type {}
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/dumux/multidomain/fvassembler.hh`</span>
Timo Koch's avatar
Timo Koch committed

## 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
   }
};
```
<span style="font-size: 0.4em; position: relative; top: -38px; color: gray;">File: `dumux/dumux/multidomain/fvassembler.hh`</span>

# Exercise
## Exercise

* Go to [Properties exercise](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux-course/-/tree/master/exercises/exercise-properties)