From 15db61074e5e37cbb22873eb71ecc9f1bef68c5a Mon Sep 17 00:00:00 2001
From: Timo Koch <timokoch@math.uio.no>
Date: Sat, 25 Mar 2023 14:49:38 +0100
Subject: [PATCH] [doxygen] Add property system description from handbook

---
 doc/doxygen/groups/core.md               |   2 -
 doc/doxygen/groups/details/properties.md | 427 +++++++++++++++++++++++
 2 files changed, 427 insertions(+), 2 deletions(-)
 create mode 100644 doc/doxygen/groups/details/properties.md

diff --git a/doc/doxygen/groups/core.md b/doc/doxygen/groups/core.md
index 4ba7de9a5a..cd0769fc22 100644
--- a/doc/doxygen/groups/core.md
+++ b/doc/doxygen/groups/core.md
@@ -3,13 +3,11 @@
 <!-- Properties -->
 
 @defgroup Properties Properties and the property systems
-@brief Basic properties of all models in DuMu<sup>x</sup>
 @ingroup Core
 
 <!-- Parameters -->
 
 @defgroup Parameters Parameters and runtime configuration
-@brief Basic properties of all models in DuMu<sup>x</sup>
 @ingroup Core
 
 <!-- Discretization -->
diff --git a/doc/doxygen/groups/details/properties.md b/doc/doxygen/groups/details/properties.md
new file mode 100644
index 0000000000..ee2fd08e3d
--- /dev/null
+++ b/doc/doxygen/groups/details/properties.md
@@ -0,0 +1,427 @@
+@addtogroup Properties
+
+The DuMu<sup>x</sup> property system is based on the concept of type traits
+with added inheritance. It is implemented using template metaprogramming.
+
+In the context of the DuMu<sup>x</sup> property system, a property is an arbitrary
+class which may contain type definitions, values and methods.
+Just like normal classes, properties can be arranged in hierarchies. In
+the context of the DuMu<sup>x</sup> property system, nodes of the inheritance
+hierarchy are called **type tags**.
+
+It also supports property **nesting**. Property nesting means that the definition of
+a property can depend on the value of other properties which may be
+defined for arbitrary levels of the inheritance hierarchy.
+
+This section gives a high level overview over the property system's design and principle ideas
+illustrated by self-contained examples.
+
+# How to use the property system
+
+All source files which use the property system should include
+the header file [dumux/common/properties.hh](https://git.iws.uni-stuttgart.de/dumux-repositories/dumux/-/blob/master/dumux/common/properties.hh).
+Declaration of type tags and property tags as well as defining properties must be done inside the
+namespace Dumux::Properties.
+
+## Defining type tags
+
+New nodes in the type tag hierarchy can be defined in the Dumux::Properties::TTag namespace using
+
+```cpp
+// Create new type tags
+namespace TTag {
+struct NewTypeTagName { using InheritsFrom = std::tuple<BaseTagName1, BaseTagName2, ...>; };
+} // end namespace TTag
+```
+
+where the `InheritsFrom` alias is optional.
+To avoid inconsistencies in the hierarchy, each type tag may be defined only
+once for a program. If you call Dumux::GetProp the property system will first look for the properties defined in
+`BaseTagName1` in the `InheritsFrom` list.
+If a defined property is found this property is returned.
+If no defined property is found the search will continue in the ancestors of `BaseTagName1`.
+If again no defined property is found the search will continue in the second `BaseTagName2` in the list, and so on.
+If no defined property is found at all, a compiler error is triggered.
+
+Example:
+```cpp
+namespace Dumux::Properties::TTag {
+struct MyBaseTypeTag1 {};
+struct MyBaseTypeTag2 {};
+
+struct MyDerivedTypeTag
+{
+    using InheritsFrom = std::tuple<
+        MyBaseTypeTag1, MyBaseTypeTag2
+    >;
+};
+} // end namespace Dumux::Properties::TTag
+```
+
+## Defining new properties
+New property tags are defined using the macro DUMUX_DEFINE_PROPERTY, e.g.
+
+```cpp
+namespace Dumux::Properties {
+DUMUX_DEFINE_PROPERTY(MyPropertyTag)
+} // end namespace Dumux::Properties
+```
+
+Essentially this corresponds to the following code
+
+```cpp
+namespace Dumux::Properties {
+template<class TypeTag, class MyTypeTag>
+struct MyPropertyTag { using type = UndefinedProperty; };
+} // end namespace Dumux::Properties
+```
+
+If you need to forward declare a property you can use
+
+```cpp
+// forward declaration
+namespace Dumux::Properties {
+template<class TypeTag, class MyTypeTag>
+struct NewPropTagName;
+} // end namespace Dumux::Properties
+```
+
+### Specializing properties
+
+The value of a property on a given node of the type tag hierarchy is
+defined by means of [partial template specialization](https://en.cppreference.com/w/cpp/language/partial_specialization)
+
+```cpp
+template<class TypeTag>
+struct PropertyTagName<TypeTag, TTag::TypeTagName>
+{
+  // arbitrary body of a struct
+};
+```
+
+where here the property `PropertyTagName` is specialized
+for the tag `TTag::TypeTagName`.
+The body typically contains either the [type alias](https://en.cppreference.com/w/cpp/language/type_alias)
+`type`, or a `static constexpr` data member `value`.
+However, you can of course write in the body whatever you like.
+
+```cpp
+template<class TypeTag>
+struct PropertyTagName<TypeTag, TTag::TypeTagName> { using type = <type>; };
+
+template<class TypeTag>
+struct PropertyTagName<TypeTag, TTag::TypeTagName> { static constexpr bool value = <booleanValue>; };
+
+template<class TypeTag>
+struct PropertyTagName<TypeTag, TTag::TypeTagName> { static constexpr int value = <integerValue>; };
+```
+
+Here is an example including a type tag, property definitions and specializations:
+
+```cpp
+namespace Dumux::Properties {
+
+// Create new type tag
+namespace TTag {
+struct MyTypeTag {};
+} // end namespace TTag
+
+// Define some properties
+DUMUX_DEFINE_PROPERTY(MyCustomProperty)
+DUMUX_DEFINE_PROPERTY(MyType)
+DUMUX_DEFINE_PROPERTY(MyBoolValue)
+DUMUX_DEFINE_PROPERTY(MyIntValue)
+DUMUX_DEFINE_PROPERTY(MyScalarValue)
+
+// Set the properties for the new type tag
+template<class TypeTag>
+struct MyCustomProperty<TypeTag, TTag::MyTypeTag>
+{
+    static void print()
+    { std::cout << "Hello, World!\n"; }
+};
+
+template<class TypeTag>
+struct MyType<TypeTag, TTag::MyTypeTag> { using type = unsigned int; };
+
+template<class TypeTag>
+struct MyBoolValue<TypeTag, TTag::MyTypeTag> { static constexpr bool value = true; };
+
+template<class TypeTag>
+struct MyIntValue<TypeTag, TTag::MyTypeTag> { static constexpr int value = 12345; };
+
+template<class TypeTag>
+struct MyScalarValue<TypeTag, TTag::MyTypeTag> { static constexpr double value = 12345.67890; };
+
+} // end namespace Dumux::Properties
+```
+
+## Retrieving property values
+
+The type of a property can be retrieved using
+
+```cpp
+using Prop = GetProp<TypeTag, Properties::PropertyTag>;
+```
+
+There is a helper struct and a helper function to retrieve the `type` and `value` members of a property
+
+```cpp
+using PropType = GetPropType<TypeTag, Properties::PropertyTag>;
+constexpr auto propValue = getPropValue<TypeTag, Properties::PropertyTag>();
+```
+
+Example:
+
+```cpp
+template <TypeTag>
+class MyClass {
+    // retrieve the ::value attribute of the 'UseMoles' property
+    static constexpr bool useMoles = getPropValue<TypeTag, Properties::UseMoles>();
+    static constexpr bool useMoles2 = GetProp<TypeTag, Properties::UseMoles>::value; // equivalent
+
+    // retrieve the ::type attribute of the 'Scalar' property
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using Scalar2 = GetProp<TypeTag, Properties::Scalar>::type; // equivalent
+};
+```
+
+## Nesting property definitions
+
+Inside property definitions there is access to all other properties
+which are defined somewhere on the type tag hierarchy. The node for
+which the current property is requested is available via the template argument
+`TypeTag`. Inside property class bodies `GetPropType` can be used to
+retrieve other properties and create aliases.
+
+Example:
+
+```cpp
+template<class TypeTag>
+struct Vector<TypeTag, TTag::MyModelTypeTag>
+{
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using type = std::vector<Scalar>;
+};
+```
+
+# A self-contained property example
+
+As a concrete example, let us consider some kinds of cars: Compact
+cars, sedans, trucks, pickups, military tanks and the Hummer-H1 sports
+utility vehicle. Since all these cars share some characteristics, it
+makes sense to inherit those from the closest matching car type and
+only specify the properties which are different. Thus, an inheritance
+diagram for the car types above might look like outlined in the figure.
+
+@mermaid{prop_example}
+
+## Defining type tags, properties, and specializations
+
+Using the DuMu<sup>x</sup> property system,
+this type hierarchy with inheritance is
+defined by:
+
+```cpp
+#include <dumux/common/propertysystem.hh>
+#include <iostream>
+
+namespace Dumux::Properties::TTag {
+struct CompactCar {};
+struct Truck {};
+struct Tank {};
+
+struct Sedan { using InheritsFrom = std::tuple<CompactCar>; };
+struct Pickup { using InheritsFrom = std::tuple<Truck, Sedan>; };
+struct HummerH1 { using InheritsFrom = std::tuple<Tank, Pickup>; };
+} // end namespace Dumux::Properties::TTag
+```
+
+The Figure lists a few property names which
+make sense for at least one of the nodes.
+These property names can be defined as
+follows:
+
+```cpp
+template<class TypeTag, class MyTypeTag>
+struct GasUsage { using type = UndefinedProperty; }; // [l/100km]
+template<class TypeTag, class MyTypeTag>
+struct TopSpeed { using type = UndefinedProperty; }; // [km/h]
+template<class TypeTag, class MyTypeTag>
+struct NumSeats { using type = UndefinedProperty; }; // []
+template<class TypeTag, class MyTypeTag>
+struct AutomaticTransmission { using type = UndefinedProperty; }; // true/false
+template<class TypeTag, class MyTypeTag>
+struct CannonCaliber { using type = UndefinedProperty; }; // [mm]
+template<class TypeTag, class MyTypeTag>
+struct Payload { using type = UndefinedProperty; }; // [t]
+```
+
+So far, the inheritance hierarchy and the property names are completely
+separate. What is missing is setting some values for the property
+names on specific nodes of the inheritance hierarchy. Let us assume
+the following:
+
+* For a compact car, the top speed is the gas usage per 100 km
+  times 30, the number of seats is 5 and the gas usage is 4 l/100km.
+* A truck is by law limited to 100 km/h top speed, the number
+  of seats is 2, it uses 18 l/100km and has a cargo payload of 35 tons.
+* A tank exhibits a top speed of 60 km/h, uses 65 l/100km
+  and features a 120 mm diameter cannon
+* A sedan has a gas usage of 7 l/100km, as well as an automatic
+  transmission. In every other aspect it is like a compact car.
+* A pick-up truck has a top speed of 120 km/h and a payload of
+  5 tons. In every other aspect it is like a sedan or a truck but if in
+  doubt, it is more like a truck.
+* The Hummer-H1 SUV exhibits the same top speed as a pick-up
+  truck. In all other aspects it is similar to a pickup and a tank,
+  but, if in doubt, more like a tank.
+
+Using the DuMu<sup>x</sup> property system, these assumptions are formulated
+using
+
+```cpp
+template<class TypeTag>
+struct TopSpeed<TypeTag, TTag::CompactCar>
+{
+    static constexpr int value
+        = getPropValue<TypeTag, Properties::GasUsage>() * 30;
+};
+
+template<class TypeTag>
+struct NumSeats<TypeTag, TTag::CompactCar>
+{ static constexpr int value = 5; };
+
+template<class TypeTag>
+struct GasUsage<TypeTag, TTag::CompactCar>
+{ static constexpr int value = 4; };
+
+template<class TypeTag>
+struct TopSpeed<TypeTag, TTag::Truck>
+{ static constexpr int value = 100; };
+
+template<class TypeTag>
+struct NumSeats<TypeTag, TTag::Truck>
+{ static constexpr int value = 2; };
+
+template<class TypeTag>
+struct GasUsage<TypeTag, TTag::Truck>
+{ static constexpr int value = 18; };
+
+template<class TypeTag>
+struct Payload<TypeTag, TTag::Truck>
+{ static constexpr int value = 35; };
+
+template<class TypeTag>
+struct TopSpeed<TypeTag, TTag::Tank>
+{ static constexpr int value = 60; };
+
+template<class TypeTag>
+struct GasUsage<TypeTag, TTag::Tank>
+{ static constexpr int value = 65; };
+
+template<class TypeTag>
+struct CannonCaliber<TypeTag, TTag::Tank>
+{ static constexpr int value = 120; };
+
+template<class TypeTag>
+struct GasUsage<TypeTag, TTag::Sedan>
+{ static constexpr int value = 7; };
+
+template<class TypeTag>
+struct AutomaticTransmission<TypeTag, TTag::Sedan>
+{ static constexpr bool value = true; };
+
+template<class TypeTag>
+struct TopSpeed<TypeTag, TTag::Pickup>
+{ static constexpr int value = 120; };
+
+template<class TypeTag>
+struct Payload<TypeTag, TTag::Pickup>
+{ static constexpr int value = 5; };
+
+template<class TypeTag>
+struct TopSpeed<TypeTag, TTag::HummerH1>
+{
+    static constexpr int value
+        = getPropValue<TypeTag, TTag::Pickup::TopSpeed<TypeTag>>();
+};
+```
+
+## Property type alias version
+
+The above hierarchy can also be written in a more terse notation using property type aliases.
+For this to work, the properties _must_ be defined with the DUMUX_DEFINE_PROPERTY macro.
+
+```cpp
+#include <type_traits>
+#include <dumux/common/properties/propertysystem.hh>
+
+namespace Dumux::Properties {
+DUMUX_DEFINE_PROPERTY(GasUsage)
+DUMUX_DEFINE_PROPERTY(TopSpeed)
+DUMUX_DEFINE_PROPERTY(NumSeats)
+DUMUX_DEFINE_PROPERTY(AutomaticTransmission)
+DUMUX_DEFINE_PROPERTY(CannonCaliber)
+DUMUX_DEFINE_PROPERTY(Payload)
+} // end namespace Dumux::Properties
+
+namespace Dumux::Properties::TTag {
+struct CompactCar {
+    template<class TypeTag>
+    using TopSpeed = std::integral_constant<int, 30*getPropValue<TypeTag, Properties::GasUsage>()>;
+    using NumSeats = std::integral_constant<int, 5>;
+    using GasUsage = std::integral_constant<int, 4>;
+};
+
+struct Truck {
+    using TopSpeed = std::integral_constant<int, 100>;
+    using NumSeats = std::integral_constant<int, 2>;
+    using GasUsage = std::integral_constant<int, 18>;
+    using Payload = std::integral_constant<int, 35>;
+};
+
+struct Tank {
+    using TopSpeed = std::integral_constant<int, 60>;
+    using GasUsage = std::integral_constant<int, 18>;
+    using CannonCaliber = std::integral_constant<int, 120>;
+};
+
+struct Sedan {
+    using InheritsFrom = std::tuple<CompactCar>;
+    using GasUsage = std::integral_constant<int, 7>;
+    using AutomaticTransmission = std::true_type;
+};
+
+struct Pickup {
+    using InheritsFrom = std::tuple<Truck, Sedan>;
+    using TopSpeed = std::integral_constant<int, 120>;
+    using Payload = std::integral_constant<int, 5>;
+};
+
+struct HummerH1 {
+    using InheritsFrom = std::tuple<Tank, Pickup>;
+    using TopSpeed = std::integral_constant<int, getPropValue<Pickup, Properties::TopSpeed>()>;
+};
+} // end namespace Dumux::Properties::TTag
+```
+
+## Retrieving properties
+
+The property values can be retrieved with Dumux::getPropValue and some diagnostic messages can
+be generated. For example
+
+```cpp
+int main()
+{
+    std::cout << "-- Top speed of sedan: " << getPropValue<Properties::TTag::Sedan, Properties::TopSpeed>() << "\n";
+    std::cout << "-- Top speed of truck: " << getPropValue<Properties::TTag::Truck, Properties::TopSpeed>() << "\n";
+}
+```
+
+will yield the following output:
+
+```sh
+-- Top speed of sedan: 210
+-- Top speed of truck: 100
+```
-- 
GitLab