From 6a3fa8dfe4e7413583bb8747ae86b027c0878463 Mon Sep 17 00:00:00 2001
From: Andreas Lauser <and@poware.org>
Date: Tue, 20 Sep 2011 16:20:34 +0000
Subject: [PATCH] property system: improve introspection

now it is possible to print where the point of definition and the
inheritance structure for all properties of a given type tag. for
properties defined using the convenience macros SET_*_PROP it is even
possible to print their value. the generic startup routines plus
test_2p have been adapted to print everything. todo: introduce a
parameter which allows to turn of the output at runtime.

git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/trunk@6637 2fb0f335-1f38-0410-981e-8018bf24f1b0
---
 dumux/common/propertysystem.hh                | 696 +++++++++++-------
 dumux/common/start.hh                         |  36 +-
 test/boxmodels/2p/lensproblem.hh              |   7 +-
 test/boxmodels/2p/test_2p.cc                  |   4 +-
 .../propertysystem/test_propertysystem.cc     |  28 +-
 5 files changed, 462 insertions(+), 309 deletions(-)

diff --git a/dumux/common/propertysystem.hh b/dumux/common/propertysystem.hh
index ef74c736b2..fd5f664ffb 100644
--- a/dumux/common/propertysystem.hh
+++ b/dumux/common/propertysystem.hh
@@ -1,5 +1,5 @@
 /*****************************************************************************
- *   Copyright (C) 2009 by Andreas Lauser                                    *
+ *   Copyright (C) 2009-2011 by Andreas Lauser                               *
  *   Institute of Hydraulic Engineering                                      *
  *   University of Stuttgart, Germany                                        *
  *   email: <givenname>.<name>@iws.uni-stuttgart.de                          *
@@ -49,6 +49,16 @@
 // string formating
 #include <boost/format.hpp>
 
+#include <dune/common/classname.hh>
+
+#include <map>
+#include <set>
+#include <list>
+#include <string>
+#include <iostream>
+#include <boost/lexical_cast.hpp>
+
+#include <string.h>
 
 namespace Dumux
 {
@@ -56,17 +66,48 @@ namespace Properties
 {
 #if !defined NO_PROPERTY_INTROSPECTION
 //! Internal macro which is only required if the property introspection is enabled
-#define PROP_INFO_(EffTypeTagName, PropTagName) \
+#define PROP_INFO_(EffTypeTagName, PropKind, PropTagName, PropValue)    \
     template <>                                                         \
-    struct PropertyInfo< TTAG(EffTypeTagName), PTAG(PropTagName) >      \
+    struct PropertyInfo<TTAG(EffTypeTagName), PTAG(PropTagName)>        \
     {                                                                   \
-        static std::string propertyName() { return #PropTagName ; }     \
-        static std::string fileDefined() { return __FILE__; }           \
-        static int lineDefined() { return __LINE__; }                   \
-    };
+    static int init() {                                                 \
+        PropertyRegistryKey key(                                        \
+            /*effTypeTagName=*/ Dune::className<TTAG(EffTypeTagName)>(), \
+            /*kind=*/PropKind,                                          \
+            /*name=*/#PropTagName,                                      \
+            /*value=*/PropValue,                                        \
+            /*file=*/__FILE__,                                          \
+            /*line=*/__LINE__);                                         \
+        PropertyRegistry::addKey(key);                                  \
+        return 0;                                                       \
+    };                                                                  \
+    static int foo;                                                     \
+    };                                                                  \
+int PropertyInfo<TTAG(EffTypeTagName), PTAG(PropTagName)>::foo =        \
+    PropertyInfo<TTAG(EffTypeTagName), PTAG(PropTagName)>::init();
+
+#define FA_TTAG_(TypeTagName, ...) TTAG(TypeTagName)
+
+//! Internal macro which is only required if the property introspection is enabled
+#define TTAG_INFO_(...)                                                 \
+    template <>                                                         \
+    struct TypeTagInfo<FA_TTAG_(__VA_ARGS__)>                           \
+    {                                                                   \
+        static int init() {                                             \
+        TypeTagRegistry::addChildren<__VA_ARGS__ >();                   \
+        return 0;                                                       \
+    };                                                                  \
+    static int foo;                                                     \
+    };                                                                  \
+int TypeTagInfo<FA_TTAG_(__VA_ARGS__)>::foo =                           \
+    TypeTagInfo<FA_TTAG_(__VA_ARGS__)>::init();
+
 #else
 //! Internal macro which is only required if the property introspection is enabled
-#define PROP_INFO_(EffTypeTagName, PropTagName)
+//!
+//! Don't do anything if introspection is disabled
+#define PROP_INFO_(EffTypeTagName, PropKind, PropTagName, PropValue)
+#define TTAG_INFO_(EffTypeTagName, ...)
 #endif
 
 // some macros for simplification
@@ -98,13 +139,13 @@ namespace Properties
  * // preceedence over those defined for FooTypeTag:
  * NEW_TYPE_TAG(FooBarTypeTag, INHERITS_FROM(FooTypeTag, BarTypeTag));
  */
-#define NEW_TYPE_TAG(TypeTagName, ...) \
+#define NEW_TYPE_TAG(TypeTagName, ...)                              \
     namespace TTag {                                                \
     struct TypeTagName : public TypeTag<TypeTagName, ##__VA_ARGS__> \
-    {                                                               \
-        static const std::string name() { return #TypeTagName ; }   \
-    };                                                              \
-    } extern int semicolonHack_
+    { };                                                            \
+    TTAG_INFO_(TypeTagName, ##__VA_ARGS__)                          \
+    }                                                               \
+    extern int semicolonHack_
 
 /*!
  * \brief Syntactic sugar for NEW_TYPE_TAG.
@@ -128,13 +169,46 @@ namespace Properties
 #define NEW_PROP_TAG(PTagName) \
     namespace PTag {                                       \
     struct PTagName; } extern int semicolonHack_
-/*                                                         \
-    {                                                      \
-        static const char *name() { return #PTagName ;};   \
-    };                                                     \
-    } extern int semicolonHack_
-*/
 
+/*!
+ * \brief Set the default for a property.
+ *
+ * SET_PROP_DEFAULT works exactly like SET_PROP, except that it does
+ * not require an effective type tag. Defaults are used whenever a
+ * property was not explicitly set or explicitly unset for a type tag.
+ *
+ * Example:
+ *
+ * // set a default for the blabbPropTag property tag
+ * SET_PROP_DEFAULT(blabbPropTag)
+ * {
+ *    static const int value = 3;
+ * };
+ */
+#define SET_PROP_DEFAULT(PropTagName) \
+    template <class TypeTag>                                            \
+    struct DefaultProperty<TypeTag, PTAG(PropTagName)>;                 \
+    PROP_INFO_(__Default,                                               \
+               /*kind=*/"<opaque>",                                     \
+               PropTagName,                                             \
+               /*value=*/"<opaque>")                                    \
+    template <class TypeTag>                                            \
+    struct DefaultProperty<TypeTag, PTAG(PropTagName) >
+
+//! Internal macro
+#define SET_PROP_(EffTypeTagName, PropKind, PropTagName, PropValue) \
+    template <class TypeTag>                                        \
+    struct Property<TypeTag,                                        \
+                    TTAG(EffTypeTagName),                           \
+                    PTAG(PropTagName)>;                             \
+    PROP_INFO_(EffTypeTagName,                                      \
+               /*kind=*/PropKind,                                   \
+               PropTagName,                                         \
+               /*value=*/PropValue)                                 \
+    template <class TypeTag>                                        \
+    struct Property<TypeTag, \
+                    TTAG(EffTypeTagName), \
+                    PTAG(PropTagName) >
 
 /*!
  * \brief Set a property for a specific type tag.
@@ -165,44 +239,18 @@ namespace Properties
  */
 #define SET_PROP(EffTypeTagName, PropTagName) \
     template <class TypeTag>                                    \
-    struct Property<TypeTag, \
-                    TTAG(EffTypeTagName), \
+    struct Property<TypeTag,                                    \
+                    TTAG(EffTypeTagName),                       \
                     PTAG(PropTagName)>;                         \
-    PROP_INFO_(EffTypeTagName, PropTagName) \
+    PROP_INFO_(EffTypeTagName,                                  \
+               /*kind=*/"opaque",                               \
+               PropTagName,                                     \
+               /*value=*/"<opaque>")                            \
     template <class TypeTag>                                    \
     struct Property<TypeTag, \
                     TTAG(EffTypeTagName), \
                     PTAG(PropTagName) >
 
-/*!
- * \brief Set the default for a property.
- *
- * SET_PROP_DEFAULT works exactly like SET_PROP, except that it does
- * not require an effective type tag. Defaults are used whenever a
- * property was not explicitly set or explicitly unset for a type tag.
- *
- * Example:
- *
- * // set a default for the blabbPropTag property tag
- * SET_PROP_DEFAULT(blabbPropTag)
- * {
- *    static const int value = 3;
- * };
- */
-#define SET_PROP_DEFAULT(PropTagName) \
-    template <class TypeTag>                                            \
-    struct DefaultProperty<TypeTag, PTAG(PropTagName)>;                 \
-    template <>                                                         \
-    struct PropertyInfo< void, PTAG(PropTagName) >                      \
-    {                                                                   \
-        static std::string propertyName() { return #PropTagName ; }     \
-        static std::string typeTagName() { return "*" ; }               \
-        static std::string fileDefined() { return __FILE__; }           \
-        static int lineDefined() { return __LINE__; }                   \
-    };                                                                  \
-    template <class TypeTag>                                            \
-    struct DefaultProperty<TypeTag, PTAG(PropTagName) >
-
 /*!
  * \brief Explicitly unset a property for a type tag.
  *
@@ -214,15 +262,18 @@ namespace Properties
  * // make the blabbPropTag property undefined for the BarTypeTag.
  * UNSET_PROP(BarTypeTag, blabbPropTag);
  */
-#define UNSET_PROP(EffTypeTagName, PropTagName) \
+#define UNSET_PROP(EffTypeTagName, PropTagName)                 \
     template <>                                                 \
-    struct PropertyUnset<TTAG(EffTypeTagName), \
+    struct PropertyUnset<TTAG(EffTypeTagName),                  \
                          PTAG(PropTagName) >;                   \
-    PROP_INFO_(EffTypeTagName, PropTagName) \
+    PROP_INFO_(EffTypeTagName,                                  \
+               /*kind=*/"unset",                                \
+               PropTagName,                                     \
+               /*value=*/"<none>")                              \
     template <>                                                 \
-    struct PropertyUnset<TTAG(EffTypeTagName), \
+    struct PropertyUnset<TTAG(EffTypeTagName),                  \
                          PTAG(PropTagName) >                    \
-        : public PropertyExplicitlyUnset \
+        : public PropertyExplicitlyUnset                        \
         {}
 
 /*!
@@ -230,8 +281,11 @@ namespace Properties
  *
  * The constant can be accessed by the 'value' attribute.
  */
-#define SET_INT_PROP(EffTypeTagName, PropTagName, Value) \
-    SET_PROP(EffTypeTagName, PropTagName) \
+#define SET_INT_PROP(EffTypeTagName, PropTagName, Value)        \
+    SET_PROP_(EffTypeTagName,                                   \
+              /*kind=*/"integer",                               \
+              PropTagName,                                      \
+              /*value=*/#Value)                                 \
     {                                                           \
         typedef int type;                                       \
         static constexpr int value = Value;                     \
@@ -242,11 +296,14 @@ namespace Properties
  *
  * The constant can be accessed by the 'value' attribute.
  */
-#define SET_BOOL_PROP(EffTypeTagName, PropTagName, Value) \
-    SET_PROP(EffTypeTagName, PropTagName) \
-    {                                                      \
-        typedef bool type;                                 \
-        static constexpr bool value = Value;               \
+#define SET_BOOL_PROP(EffTypeTagName, PropTagName, Value)       \
+    SET_PROP_(EffTypeTagName,                                   \
+              /*kind=*/"boolean",                               \
+              PropTagName,                                      \
+              /*value=*/#Value)                                 \
+    {                                                           \
+        typedef bool type;                                      \
+        static constexpr bool value = Value;                    \
     }
 
 /*!
@@ -254,10 +311,13 @@ namespace Properties
  *
  * The type can be accessed by the 'type' attribute.
  */
-#define SET_TYPE_PROP(EffTypeTagName, PropTagName, Type) \
-    SET_PROP(EffTypeTagName, PropTagName) \
-    {                                                      \
-        typedef Type type;                                 \
+#define SET_TYPE_PROP(EffTypeTagName, PropTagName, Type)        \
+    SET_PROP_(EffTypeTagName,                                   \
+              /*kind=*/"type",                                  \
+              PropTagName,                                      \
+              /*value=*/#Type)                                  \
+    {                                                           \
+        typedef Type type;                                      \
     }
 
 /*!
@@ -267,8 +327,11 @@ namespace Properties
  * use this macro, the property tag "Scalar" needs to be defined for
  * the real type tag.
  */
-#define SET_SCALAR_PROP(EffTypeTagName, PropTagName, Value) \
-    SET_PROP(EffTypeTagName, PropTagName) \
+#define SET_SCALAR_PROP(EffTypeTagName, PropTagName, Value)             \
+    SET_PROP_(EffTypeTagName,                                           \
+              /*kind=*/"scalar",                                        \
+              PropTagName,                                              \
+              /*value=*/#Value)                                         \
     {                                                                   \
         typedef typename GET_PROP_TYPE(TypeTag, PTAG(Scalar)) Scalar;   \
     public:                                                             \
@@ -284,7 +347,7 @@ namespace Properties
  * the 'typename' keyword.
  */
 #define GET_PROP(TypeTag, PropTag) \
-    ::Dumux::Properties::GetProperty< TypeTag, PropTag>::p
+    ::Dumux::Properties::GetProperty<TypeTag, PropTag>::p
 
 /*!
  * \brief Access the 'value' attribute of a property for a type tag.
@@ -294,7 +357,7 @@ namespace Properties
  * 'value', this yields a compiler error.
  */
 #define GET_PROP_VALUE(TypeTag, PropTag) \
-    ::Dumux::Properties::GetProperty< TypeTag, PropTag>::p::value
+    ::Dumux::Properties::GetProperty<TypeTag, PropTag>::p::value
 
 /*!
  * \brief Access the 'type' attribute of a property for a type tag.
@@ -305,8 +368,7 @@ namespace Properties
  * within a template, it must be preceeded by the 'typename' keyword.
  */
 #define GET_PROP_TYPE(TypeTag, PropTag) \
-    ::Dumux::Properties::GetProperty< TypeTag, \
-                                     PropTag>::p::type
+    ::Dumux::Properties::GetProperty<TypeTag, PropTag>::p::type
 
 #if !defined NO_PROPERTY_INTROSPECTION
 /*!
@@ -323,10 +385,9 @@ namespace Properties
  *    std::cout << PROP_DIAGNOSTIC(FooBarTypeTag, blabbPropTag) << "\n";
  * };
  */
-#define PROP_DIAGNOSTIC(TypeTag, PropTag) \
-    ::Dumux::Properties::propertyDiagnostic< TypeTag, \
-                                            TypeTag, \
-                                            PropTag>::message()
+#define PROP_DIAGNOSTIC(TypeTag, PropTagName) \
+    ::Dumux::Properties::getDiagnostic<TypeTag>(#PropTagName)
+
 #else
 /*!
  * \brief Return a human readable diagnostic message how exactly a
@@ -356,6 +417,137 @@ namespace Properties
 namespace PTag {}
 namespace TTag {}
 
+#if !defined NO_PROPERTY_INTROSPECTION
+
+namespace TTag
+{
+template <class EffTypeTag>
+struct TypeTagInfo
+{};
+}
+
+template <class EffTypeTagName, class PropTagName>
+struct PropertyInfo
+{};
+class PropertyRegistryKey
+{
+public:
+    PropertyRegistryKey()
+    {};
+
+    PropertyRegistryKey(const std::string &effTypeTagName,
+                        const std::string &propertyKind,
+                        const std::string &propertyName,
+                        const std::string &propertyValue,
+                        const std::string &fileDefined,
+                        int lineDefined)
+        : effTypeTagName_(effTypeTagName)
+        , propertyKind_(propertyKind)
+        , propertyName_(propertyName)
+        , propertyValue_(propertyValue)
+        , fileDefined_(fileDefined)
+        , lineDefined_(lineDefined)
+    {
+    };
+
+    // copy constructor
+    PropertyRegistryKey(const PropertyRegistryKey &v)
+        : effTypeTagName_(v.effTypeTagName_)
+        , propertyKind_(v.propertyKind_)
+        , propertyName_(v.propertyName_)
+        , propertyValue_(v.propertyValue_)
+        , fileDefined_(v.fileDefined_)
+        , lineDefined_(v.lineDefined_)
+    {};
+
+    const std::string &effTypeTagName() const
+    { return effTypeTagName_; }
+    const std::string &propertyKind() const
+    { return propertyKind_; }
+    const std::string &propertyName() const
+    { return propertyName_; }
+    const std::string &propertyValue() const 
+    { return propertyValue_; }
+    const std::string &fileDefined() const
+    { return fileDefined_; }
+    int lineDefined() const
+    { return lineDefined_; }
+
+private:
+    std::string effTypeTagName_;
+    std::string propertyKind_;
+    std::string propertyName_;
+    std::string propertyValue_;
+    std::string fileDefined_;
+    int lineDefined_;
+};
+
+class PropertyRegistry
+{
+public:
+    typedef std::map<std::string, PropertyRegistryKey> KeyList;
+    typedef std::map<std::string, KeyList> KeyListMap;
+
+    static void addKey(const PropertyRegistryKey &key)
+    {
+        keys_[key.effTypeTagName()][key.propertyName()] = key;
+    }
+
+    static const PropertyRegistryKey &getKey(const std::string &effTypeTagName,
+                                             const std::string &propertyName)
+    {
+        return keys_[effTypeTagName][propertyName];
+    };
+
+    static const KeyList &getKeys(const std::string &effTypeTagName)
+    {
+        return keys_[effTypeTagName];
+    };
+
+private:
+    static KeyListMap keys_;
+};
+PropertyRegistry::KeyListMap PropertyRegistry::keys_;
+
+class TypeTagRegistry
+{
+public:
+    typedef std::list<std::string> ChildrenList;
+    typedef std::map<std::string, ChildrenList> ChildrenListMap;
+    
+    template <class TypeTag,
+              class Child1 = void, 
+              class Child2 = void, 
+              class Child3 = void, 
+              class Child4 = void, 
+              class Child5 = void>
+    static void addChildren()
+    {
+        std::string typeTagName = Dune::className<TypeTag>();
+        if (typeid(Child1) != typeid(void))
+            keys_[typeTagName].push_front(Dune::className<Child1>());
+        if (typeid(Child2) != typeid(void))
+            keys_[typeTagName].push_front(Dune::className<Child2>());
+        if (typeid(Child3) != typeid(void))
+            keys_[typeTagName].push_front(Dune::className<Child3>());
+        if (typeid(Child4) != typeid(void))
+            keys_[typeTagName].push_front(Dune::className<Child4>());
+        if (typeid(Child5) != typeid(void))
+            keys_[typeTagName].push_front(Dune::className<Child5>());
+    };
+
+    static const ChildrenList &children(const std::string &typeTagName)
+    {
+        return keys_[typeTagName];
+    };
+    
+private:
+    static ChildrenListMap keys_;
+};
+
+TypeTagRegistry::ChildrenListMap TypeTagRegistry::keys_;
+#endif // !defined NO_PROPERTY_INTROSPECTION
+
 using namespace boost::type_traits;
 using boost::is_void;
 using boost::is_base_of;
@@ -380,23 +572,6 @@ struct PropertyUnset : public PropertyUndefined
 {
 };
 
-//! \internal
-template <class EffectiveTypeTag, class PropertyTag>
-struct PropertyInfo
-{
-    static std::string typeTagName()
-    { return "Unknown"; }
-
-    static std::string propertyName()
-    { return "Unknown (PropertyInfo is not specialized for this property)"; }
-
-    static std::string fileDefined()
-    { return __FILE__; }
-
-    static int lineDefined()
-    { return __LINE__; }
-};
-
 //! \internal
 template <class RealTypeTag,
           class PropertyTag>
@@ -601,6 +776,8 @@ public:
     typedef Child5T Child5;
 };
 
+NEW_TYPE_TAG(__Default);
+
 //! \internal
 template <class EffectiveTypeTag,
           class PropertyTag,
@@ -662,208 +839,167 @@ struct GetProperty<TypeTag, PropertyTag, RealTypeTag, 5>
 };
 
 #if !defined NO_PROPERTY_INTROSPECTION
-//! \internal
-template <class RealTypeTag, class Tree, class PropertyTag>
-struct propertyDiagnostic
+std::string canonicalTypeTagNameToName_(const std::string &canonicalName)
+{ 
+    std::string result(canonicalName);
+    result.replace(0, strlen("Dumux::Properties::TTag::"), "");
+    return result;
+}
+
+inline bool getDiagnostic_(const std::string &typeTagName,
+                           const std::string &propTagName,
+                           std::string &result,
+                           const std::string indent)
 {
-    typedef typename Tree::SelfType EffTypeTag;
-
-    static const int inheritedFrom = propertyTagIndex<RealTypeTag, EffTypeTag, PropertyTag>::value;
-
-    static const bool explicitlyUnset = propertyExplicitlyUnsetOnTree<Tree, PropertyTag>::value;
-    static const bool explicitlyUnsetOnSelf = propertyExplicitlyUnset<Tree, PropertyTag>::value;
-
-    typedef propertyDefined<RealTypeTag, Tree, PropertyTag> definedWhere;
-
-    typedef PropertyInfo<EffTypeTag, PropertyTag>           propInfo;
-    typedef PropertyInfo<void, PropertyTag>                 propInfoDefault;
-
-    static const std::string typeTagName()
-    {
-        return Tree::SelfType::name();
-    };
-
-    static const std::string propertyName()
-    {
-        switch (inheritedFrom) {
-        case -1: return propInfoDefault::propertyName();
-        case -1000:
-        case 0: return propInfo::propertyName();
-        case 1: return Child1Diagnostic::propertyName();
-        case 2: return Child2Diagnostic::propertyName();
-        case 3: return Child3Diagnostic::propertyName();
-        case 4: return Child4Diagnostic::propertyName();
-        case 5: return Child5Diagnostic::propertyName();
-        }
-    };
-
-    typedef propertyDiagnostic<RealTypeTag, typename Tree::Child1, PropertyTag> Child1Diagnostic;
-    typedef propertyDiagnostic<RealTypeTag, typename Tree::Child2, PropertyTag> Child2Diagnostic;
-    typedef propertyDiagnostic<RealTypeTag, typename Tree::Child3, PropertyTag> Child3Diagnostic;
-    typedef propertyDiagnostic<RealTypeTag, typename Tree::Child4, PropertyTag> Child4Diagnostic;
-    typedef propertyDiagnostic<RealTypeTag, typename Tree::Child5, PropertyTag> Child5Diagnostic;
-
-
-    static std::string message(const std::string &indent="", bool topLevel=true)
-    {
-        std::string result;
-        if (topLevel) {
-            result =
-                (boost::format("%sProperty '%s' for type tag '%s'\n")
-                 %indent
-                 %propertyName()
-                 %typeTagName()
-                    ).str();
-        }
-        std::string newIndent = indent + "  ";
-
-        if (explicitlyUnsetOnSelf) {
-            result += (boost::format("%sexplicitly unset at %s:%d\n")
-                       %newIndent
-                       %propInfo::fileDefined()
-                       %propInfo::lineDefined()).str();
-            return result;
-        }
-        else if (explicitlyUnset) {
-            result += explicitlyUnsetMsg(indent);
-            return result;
-        };
-
-        switch (inheritedFrom) {
-        case -1:
-            result += newIndent;
-            result += (boost::format("default from %s:%d\n")
-                       %propInfoDefault::fileDefined()
-                       %propInfoDefault::lineDefined()).str();
-            break;
-
-        case 0:
-            result += newIndent;
-            result += (boost::format("defined at %s:%d\n")
-                       %propInfo::fileDefined()
-                       %propInfo::lineDefined()).str();
-            break;
-
-        case 1:
-            result += explicitlyUnsetOnChildMsg(indent, 5);
-            result += explicitlyUnsetOnChildMsg(indent, 4);
-            result += explicitlyUnsetOnChildMsg(indent, 3);
-            result += explicitlyUnsetOnChildMsg(indent, 2);
-            result += newIndent;
-            result += (boost::format("inherited from '%s'\n"
-                                     "%s") %
-                       Child1Diagnostic::typeTagName() %
-                       Child1Diagnostic::message(newIndent, false)).str();
-            break;
-
-        case 2:
-            result += explicitlyUnsetOnChildMsg(indent, 5);
-            result += explicitlyUnsetOnChildMsg(indent, 4);
-            result += explicitlyUnsetOnChildMsg(indent, 3);
-            result += newIndent;
-            result += (boost::format("inherited from '%s'\n"
-                                     "%s") %
-                       Child2Diagnostic::typeTagName() %
-                       Child2Diagnostic::message(newIndent, false)).str();
+    const PropertyRegistryKey *key = 0;
+
+    const PropertyRegistry::KeyList &keys =
+        PropertyRegistry::getKeys(typeTagName);
+    PropertyRegistry::KeyList::const_iterator it = keys.begin();
+    for (; it != keys.end(); ++it) {
+        if (it->second.propertyName() == propTagName) {
+            key = &it->second;
             break;
-
-        case 3:
-            result += explicitlyUnsetOnChildMsg(indent, 5);
-            result += explicitlyUnsetOnChildMsg(indent, 4);
-            result += newIndent;
-            result += (boost::format("inherited from '%s'\n"
-                                     "%s") %
-                       Child3Diagnostic::typeTagName() %
-                       Child3Diagnostic::message(newIndent, false)).str();
-            break;
-
-        case 4:
-            result += explicitlyUnsetOnChildMsg(indent, 5);
-            result += newIndent;
-            result += (boost::format("inherited from '%s'\n"
-                                     "%s") %
-                       Child4Diagnostic::typeTagName() %
-                       Child4Diagnostic::message(newIndent, false)).str();
-            break;
-
-        case 5:
-            result += newIndent;
-            result += (boost::format("inherited from '%s'\n"
-                                     "%s") %
-                       Child5Diagnostic::typeTagName() %
-                       Child5Diagnostic::message(newIndent, false)).str();
-            break;
-
-        case -1000:
-            result += boost::format("was not set anywhere\n").str();
         };
-
-        return result;
-    };
-
-    static std::string explicitlyUnsetMsg(const std::string &indent)
-    {
-        if (explicitlyUnsetOnSelf) {
-            return (boost::format("%sexplicitly unset for '%s' at %s:%d\n")
-                    %indent
-                    %typeTagName()
-                    %propInfo::fileDefined()
-                    %propInfo::lineDefined()).str();
-        }
-        else if (explicitlyUnset) {
-            std::string result = (boost::format("%sexplicitly unset for all parents of '%s':\n")
-                                  %indent
-                                  %typeTagName()).str();
-            result += explicitlyUnsetOnChildMsg(indent, 5);
-            result += explicitlyUnsetOnChildMsg(indent, 4);
-            result += explicitlyUnsetOnChildMsg(indent, 3);
-            result += explicitlyUnsetOnChildMsg(indent, 2);
-            result += explicitlyUnsetOnChildMsg(indent, 1);
-            return result;
-        };
-        return "";
+    }
+    
+    if (key) {
+        result = indent;
+        result +=
+            key->propertyKind() + " property '"
+            + key->propertyName() + "' defined on '"
+            + canonicalTypeTagNameToName_(key->effTypeTagName()) + "' at "
+            + key->fileDefined() + ":" + boost::lexical_cast<std::string>(key->lineDefined()) + "\n";
+        return true;
     }
 
-    static std::string explicitlyUnsetOnChildMsg(const std::string &indent, int unsetChild)
-    {
-        switch (unsetChild) {
-        case 5:
-            return Child5Diagnostic::explicitlyUnsetMsg(indent + "  ");
-        case 4:
-            return Child4Diagnostic::explicitlyUnsetMsg(indent + "  ");
-        case 3:
-            return Child3Diagnostic::explicitlyUnsetMsg(indent + "  ");
-        case 2:
-            return Child2Diagnostic::explicitlyUnsetMsg(indent + "  ");
-        case 1:
-            return Child1Diagnostic::explicitlyUnsetMsg(indent + "  ");
+    // print properties defined on children
+    typedef TypeTagRegistry::ChildrenList ChildrenList;
+    const ChildrenList &children = TypeTagRegistry::children(typeTagName);
+    ChildrenList::const_iterator ttagIt = children.begin();
+    std::string newIndent = indent + "  ";
+    for (; ttagIt != children.end(); ++ttagIt) {
+        if (getDiagnostic_(*ttagIt, propTagName, result, newIndent)) {
+            result.insert(0, indent + "Inherited from '" + canonicalTypeTagNameToName_(typeTagName) + "'\n");
+            return true;
         }
-        return "";
     }
-};
 
-//! \internal
-template <class RealTypeTag, class PropertyTag>
-struct propertyDiagnostic<RealTypeTag, void, PropertyTag>
+    return false;
+}
+
+template <class TypeTag>
+const std::string getDiagnostic(std::string propTagName)
 {
-    typedef PropertyInfo<void, PropertyTag>           propInfo;
+    std::string result;
+
+    std::string TypeTagName(Dune::className<TypeTag>());
+
+    propTagName.replace(0, strlen("PTag("), "");
+    int n = propTagName.length();
+    propTagName.replace(n - 1, 1, "");
+    //TypeTagName.replace(0, strlen("Dumux::Properties::TTag::"), "");
+    
+    if (!getDiagnostic_(TypeTagName, propTagName, result, "")) {
+        // check whether the property is a default property
+        const PropertyRegistry::KeyList &keys =
+            PropertyRegistry::getKeys(Dune::className<TTAG(__Default)>());
+        PropertyRegistry::KeyList::const_iterator it = keys.begin();
+        for (; it != keys.end(); ++it) {
+            const PropertyRegistryKey &key = it->second;
+            if (key.propertyName() != propTagName)
+                continue; // property already printed
+            result = "default property '" + key.propertyName()
+                + "' defined at " + key.fileDefined()
+                + ":" + boost::lexical_cast<std::string>(key.lineDefined())
+                + "\n";
+        };
+    }
 
-    static const std::string propertyName()
-    { return propInfo::propertyName(); }
 
-    static const std::string typeTagName()
-    { return "* (Default Value)"; }
+    return result;
+};
 
-    static std::string message(const std::string &ident="", bool topLevel=true)
-    {
-        return "";
+//! \internal
+template <class TypeTag>
+void print(std::ostream &os = std::cout)
+{
+    std::set<std::string> printedProps;
+    print_(Dune::className<TypeTag>(), os, "", printedProps);
+
+    // print the default properties
+    const PropertyRegistry::KeyList &keys =
+        PropertyRegistry::getKeys(Dune::className<TTAG(__Default)>());
+    PropertyRegistry::KeyList::const_iterator it = keys.begin();
+    for (; it != keys.end(); ++it) {
+        const PropertyRegistryKey &key = it->second;
+        if (printedProps.count(key.propertyName()) > 0)
+            continue; // property already printed
+        os << "  default property '" << key.propertyName()
+           << "' defined at " << key.fileDefined()
+           << ":" << key.lineDefined()
+           << "\n";
+        printedProps.insert(key.propertyName());
     };
+}
 
-    static std::string explicitlyUnsetMsg(const std::string &indent, int numUnsetChilds=5)
-    {
-        return "";
+inline void print_(const std::string &typeTagName,
+                   std::ostream &os,
+                   const std::string indent,
+                   std::set<std::string> &printedProperties)
+{
+    if (indent == "")
+        os << indent << "Properties defined for '" << canonicalTypeTagNameToName_(typeTagName) << "':\n";
+    else
+        os << indent << "Inherited from '" << canonicalTypeTagNameToName_(typeTagName) << "':\n";
+    const PropertyRegistry::KeyList &keys =
+        PropertyRegistry::getKeys(typeTagName);
+    PropertyRegistry::KeyList::const_iterator it = keys.begin();
+    for (; it != keys.end(); ++it) {
+        const PropertyRegistryKey &key = it->second;
+        if (printedProperties.count(key.propertyName()) > 0)
+            continue; // property already printed
+        
+        os << indent << "  " 
+           << key.propertyKind() << " property '" << key.propertyName() << "'";
+        if (key.propertyKind() != "opaque")
+            os << " = '" << key.propertyValue() << "'";
+        os << " defined at " << key.fileDefined()
+           << ":" << key.lineDefined()
+           << "\n";
+        printedProperties.insert(key.propertyName());
     };
+
+    // print properties defined on children
+    typedef TypeTagRegistry::ChildrenList ChildrenList;
+    const ChildrenList &children = TypeTagRegistry::children(typeTagName);
+    ChildrenList::const_iterator ttagIt = children.begin();
+    std::string newIndent = indent + "  ";
+    for (; ttagIt != children.end(); ++ttagIt) {
+        print_(*ttagIt, os, newIndent, printedProperties);
+    }
+}
+#else // !defined NO_PROPERTY_INTROSPECTION
+template <class TypeTag>
+void print(std::ostream &os = std::cout)
+{
+    std::cout <<
+        "The Dumux property system was compiled with the macro\n"
+        "NO_PROPERTY_INTROSPECTION defined.\n"
+        "No diagnostic messages this time, sorry.\n";
+}
+
+template <class TypeTag>
+const std::string getDiagnostic(std::string propTagName)
+{
+    std::string result;
+    result =
+        "The Dumux property system was compiled with the macro\n"
+        "NO_PROPERTY_INTROSPECTION defined.\n"
+        "No diagnostic messages this time, sorry.\n";
+    return result;
 };
+
 #endif // !defined NO_PROPERTY_INTROSPECTION
 
 //! \endcond
diff --git a/dumux/common/start.hh b/dumux/common/start.hh
index 6333ac1ec8..ff60b2e846 100644
--- a/dumux/common/start.hh
+++ b/dumux/common/start.hh
@@ -87,21 +87,21 @@ void printUsageInputFile(const char *progname)
  * \brief Provides a default main function for simulations requiring
  *        only a single DGF file as their grid specification.
  *
- * \tparam ProblemTypeTag  The type tag of the problem which needs to be solved
+ * \tparam TypeTag  The type tag of the problem which needs to be solved
  *
  * \param argc  The 'argc' argument of the main function
  * \param argv  The 'argv' argument of the main function
  */
-template <class ProblemTypeTag>
+template <class TypeTag>
 int startFromDGF(int argc, char **argv)
 {
 #ifdef NDEBUG
     try {
 #endif
 
-        typedef typename GET_PROP_TYPE(ProblemTypeTag, PTAG(Grid)) Grid;
-        typedef typename GET_PROP_TYPE(ProblemTypeTag, PTAG(Problem)) Problem;
-        typedef typename GET_PROP_TYPE(ProblemTypeTag, PTAG(TimeManager)) TimeManager;
+        typedef typename GET_PROP_TYPE(TypeTag, PTAG(Grid)) Grid;
+        typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem;
+        typedef typename GET_PROP_TYPE(TypeTag, PTAG(TimeManager)) TimeManager;
         typedef Dune::GridPtr<Grid> GridPointer;
 
         // initialize MPI, finalize is done automatically on exit
@@ -146,6 +146,10 @@ int startFromDGF(int argc, char **argv)
         TimeManager timeManager;
         Problem problem(timeManager, gridPtr->leafView());
         timeManager.init(problem, 0, dt, tEnd, !restart);
+
+        // print all properties
+        Dumux::Properties::print<TypeTag>();
+
         if (restart)
             problem.restart(restartTime);
         timeManager.run();
@@ -170,7 +174,7 @@ int startFromDGF(int argc, char **argv)
  *        create the grid themselves but do not require any other
  *        parameters.
  *
- * \tparam ProblemTypeTag  The type tag of the problem which needs to be solved
+ * \tparam TypeTag  The type tag of the problem which needs to be solved
  *
  * \param grid  The grid used by the simulation
  * \param argc  The 'argc' argument of the main function
@@ -216,6 +220,10 @@ int startWithGrid(const typename GET_PROP_TYPE(TypeTag, PTAG(Grid)) &grid,
         TimeManager timeManager;
         Problem problem(timeManager, grid.leafView());
         timeManager.init(problem, 0, dt, tEnd, !restart);
+
+        // print all properties
+        Dumux::Properties::print<TypeTag>();
+
         if (restart)
             problem.restart(restartTime);
         timeManager.run();
@@ -241,22 +249,22 @@ int startWithGrid(const typename GET_PROP_TYPE(TypeTag, PTAG(Grid)) &grid,
  * \brief Provides a default main function for simulations requiring
  *        only a single DGF file as their grid specification.
  *
- * \tparam ProblemTypeTag  The type tag of the problem which needs to be solved
+ * \tparam TypeTag  The type tag of the problem which needs to be solved
  *
  * \param argc  The 'argc' argument of the main function
  * \param argv  The 'argv' argument of the main function
  */
-template <class ProblemTypeTag>
+template <class TypeTag>
 int startFromInputFile(int argc, char **argv)
 {
 #ifdef NDEBUG
    try {
 #endif
 
-       typedef typename GET_PROP_TYPE(ProblemTypeTag, PTAG(Grid)) Grid;
-       typedef typename GET_PROP_TYPE(ProblemTypeTag, PTAG(Problem)) Problem;
-       typedef typename GET_PROP_TYPE(ProblemTypeTag, PTAG(TimeManager)) TimeManager;
-       typedef typename GET_PROP(ProblemTypeTag, PTAG(ParameterTree)) Params;
+       typedef typename GET_PROP_TYPE(TypeTag, PTAG(Grid)) Grid;
+       typedef typename GET_PROP_TYPE(TypeTag, PTAG(Problem)) Problem;
+       typedef typename GET_PROP_TYPE(TypeTag, PTAG(TimeManager)) TimeManager;
+       typedef typename GET_PROP(TypeTag, PTAG(ParameterTree)) Params;
        typedef Dune::GridPtr<Grid> GridPointer;
 
        // initialize MPI, finalize is done automatically on exit
@@ -323,6 +331,10 @@ int startFromInputFile(int argc, char **argv)
                gridPtr->leafView(),
                Params::tree());
        timeManager.init(problem, 0, dt, tEnd, !restart);
+       
+       // print all properties
+       Dumux::Properties::print<TypeTag>();
+
        if (restart)
            problem.restart(restartTime);
        timeManager.run();
diff --git a/test/boxmodels/2p/lensproblem.hh b/test/boxmodels/2p/lensproblem.hh
index 76a43456b8..21c47dca36 100644
--- a/test/boxmodels/2p/lensproblem.hh
+++ b/test/boxmodels/2p/lensproblem.hh
@@ -58,14 +58,11 @@ namespace Properties
 NEW_TYPE_TAG(LensProblem, INHERITS_FROM(BoxTwoP, LensSpatialParameters));
 
 // Set the grid type
-SET_PROP(LensProblem, Grid)
-{
 #if 0// HAVE_UG
-    typedef Dune::UGGrid<2> type;
+SET_TYPE_PROP(LensProblem, Grid, Dune::UGGrid<2>);
 #else
-    typedef Dune::YaspGrid<2> type;
+SET_TYPE_PROP(LensProblem, Grid, Dune::YaspGrid<2>);
 #endif
-};
 
 // Set the problem property
 SET_PROP(LensProblem, Problem)
diff --git a/test/boxmodels/2p/test_2p.cc b/test/boxmodels/2p/test_2p.cc
index ed71669351..871ff00b33 100644
--- a/test/boxmodels/2p/test_2p.cc
+++ b/test/boxmodels/2p/test_2p.cc
@@ -25,7 +25,6 @@
  * \brief test for the two-phase box model
  */
 #include "config.h"
-
 #define CUBES 1
 
 #include "lensproblem.hh"
@@ -161,6 +160,9 @@ int main(int argc, char** argv)
 
         static const int dim = Grid::dimension;
 
+        // print all properties
+        Dumux::Properties::print<TypeTag>();
+
         // initialize MPI, finalize is done automatically on exit
         Dune::MPIHelper::instance(argc, argv);
 
diff --git a/test/common/propertysystem/test_propertysystem.cc b/test/common/propertysystem/test_propertysystem.cc
index 4ef5e2c2fa..5501d938cd 100644
--- a/test/common/propertysystem/test_propertysystem.cc
+++ b/test/common/propertysystem/test_propertysystem.cc
@@ -36,16 +36,19 @@ namespace Properties {
 ///////////////////
 // Define some hierarchy of type tags:
 //
-//  CompactCar --- Sedan -_
-//                         \.
-//                          +- Pickup ---_
-//                         /              \.
-//  Truck ----------------^                \.
-//  Tank ---------------------------------- HummerH1
+//  Vehicle -- CompactCar -- Sedan -_
+//     \                            \.
+//      \                            +- Pickup ---_
+//       \                          /              \.
+//        +-- Truck ---------------^                \.
+//         \                                         \.
+//          +- Tank ----------------------------------+- HummerH1
 ///////////////////
-NEW_TYPE_TAG(CompactCar);
-NEW_TYPE_TAG(Truck);
-NEW_TYPE_TAG(Tank);
+NEW_TYPE_TAG(Vehicle);
+
+NEW_TYPE_TAG(CompactCar, INHERITS_FROM(Vehicle));
+NEW_TYPE_TAG(Truck, INHERITS_FROM(Vehicle));
+NEW_TYPE_TAG(Tank, INHERITS_FROM(Vehicle));
 
 NEW_TYPE_TAG(Sedan, INHERITS_FROM(CompactCar));
 NEW_TYPE_TAG(Pickup, INHERITS_FROM(Sedan, Truck));
@@ -65,8 +68,7 @@ NEW_PROP_TAG(Payload); // [t]
 
 ///////////////////
 // Make the AutomaticTransmission default to false
-SET_PROP_DEFAULT(AutomaticTransmission)
-{ static const bool value = false; };
+SET_BOOL_PROP(Vehicle, AutomaticTransmission, false);
 
 ///////////////////
 // Define some values for the properties on the type tags:
@@ -178,6 +180,10 @@ int main()
     std::cout << "---------------------------------------\n";
     std::cout << "-- Diagnostic messages\n";
     std::cout << "---------------------------------------\n";
+
+    std::cout << "---- All properties for Sedan ---\n";
+    Dumux::Properties::print<TTAG(Sedan)>();
+
     std::cout << "---- Message for (HummerH1, CanonCaliber) ---\n"
               << PROP_DIAGNOSTIC(TTAG(HummerH1), PTAG(CanonCaliber));
     std::cout << "---- Message for (HummerH1, GasUsage) ---\n"
-- 
GitLab