From 637b6736b2f16b5681e4b671591d43c53030aebc Mon Sep 17 00:00:00 2001
From: Dmitri Naumov <github@naumov.de>
Date: Sun, 12 May 2019 22:35:38 +0200
Subject: [PATCH] [PaL] Add possibility to check parameter's domain.

Sometimes it happens, that a used parameter is defined
on a different mesh, then the mesh node/element ids do
not point to the right entities. This is difficult to
detect at runtime (you have to look into the results)
and leads to difficult to find errors.

This implements an additional function to check the
domains of definition, and adds an optional call to the
test when the parameter is found.
---
 ParameterLib/Parameter.cpp | 19 +++++++++++++++++++
 ParameterLib/Parameter.h   |  9 +++++++++
 ParameterLib/Utils.h       | 28 +++++++++++++++++++++++-----
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/ParameterLib/Parameter.cpp b/ParameterLib/Parameter.cpp
index c535765cbc9..d7323997f73 100644
--- a/ParameterLib/Parameter.cpp
+++ b/ParameterLib/Parameter.cpp
@@ -84,4 +84,23 @@ std::unique_ptr<ParameterBase> createParameter(
     OGS_FATAL("Cannot construct a parameter of given type '%s'.", type.c_str());
 }
 
+boost::optional<std::string> isDefinedOnSameMesh(ParameterBase const& parameter,
+                                                 MeshLib::Mesh const& mesh)
+{
+    // Arbitrary domain of definition.
+    if (parameter.mesh() == nullptr)
+    {
+        return {};
+    }
+
+    // Equal meshes.
+    if (*parameter.mesh() == mesh)
+    {
+        return {};
+    }
+
+    return "The parameter's domain of definition mesh '" +
+           parameter.mesh()->getName() + "' differs from the used mesh '" +
+           mesh.getName() + "'. Both meshes must be equal.";
+}
 }  // namespace ParameterLib
diff --git a/ParameterLib/Parameter.h b/ParameterLib/Parameter.h
index 6a6ec97860f..604d00bf84f 100644
--- a/ParameterLib/Parameter.h
+++ b/ParameterLib/Parameter.h
@@ -197,4 +197,13 @@ std::unique_ptr<ParameterBase> createParameter(
              std::unique_ptr<MathLib::PiecewiseLinearInterpolation>> const&
         curves);
 
+//! Checks whether the parameter can be used on the given mesh. The parameter's
+//! domain of definition can be arbitrary (like for constant parameters), or the
+//! parameter is defined on a mesh. In the latter case that mesh must be equal
+//! to the given mesh.
+//! \returns nothing if the parameter can be used on the given mesh, or an error
+//! string otherwise.
+boost::optional<std::string> isDefinedOnSameMesh(ParameterBase const& parameter,
+                                                 MeshLib::Mesh const& mesh);
+
 }  // namespace ParameterLib
diff --git a/ParameterLib/Utils.h b/ParameterLib/Utils.h
index fd191cdb83e..a2a4dcebadd 100644
--- a/ParameterLib/Utils.h
+++ b/ParameterLib/Utils.h
@@ -33,13 +33,15 @@ ParameterBase* findParameterByName(
 /// \param parameters list of parameters in which it will be searched
 /// \param num_components the number of components of the parameters or zero if
 /// any number is acceptable
+/// \param mesh an optional mesh pointer used for test whether the parameter is
+/// defined on the given mesh. No test is performed if the pointer is a nullptr.
 ///
 /// \see The documentation of the other findParameter() function.
 template <typename ParameterDataType>
 Parameter<ParameterDataType>* findParameterOptional(
     std::string const& parameter_name,
     std::vector<std::unique_ptr<ParameterBase>> const& parameters,
-    int const num_components)
+    int const num_components, MeshLib::Mesh const* const mesh = nullptr)
 {
     // Find corresponding parameter by name.
     ParameterBase* parameter_ptr =
@@ -68,6 +70,19 @@ Parameter<ParameterDataType>* findParameterOptional(
             num_components);
     }
 
+    // Test the parameter's mesh only if there is a "test"-mesh provided.
+    if (mesh != nullptr)
+    {
+        if (auto const error = isDefinedOnSameMesh(*parameter, *mesh))
+        {
+            OGS_FATAL(
+                "The found parameter is not suitable for the use on the "
+                "required mesh.\n%s",
+                error->c_str());
+        }
+    }
+
+
     return parameter;
 }
 
@@ -78,16 +93,18 @@ Parameter<ParameterDataType>* findParameterOptional(
 /// \param parameters list of parameters in which it will be searched
 /// \param num_components the number of components of the parameters or zero if
 /// any number is acceptable
+/// \param mesh an optional mesh pointer used for test whether the parameter is
+/// defined on the given mesh. No test is performed if the pointer is a nullptr.
 ///
 /// \see The documentation of the other findParameter() function.
 template <typename ParameterDataType>
 Parameter<ParameterDataType>& findParameter(
     std::string const& parameter_name,
     std::vector<std::unique_ptr<ParameterBase>> const& parameters,
-    int const num_components)
+    int const num_components, MeshLib::Mesh const* const mesh = nullptr)
 {
     auto* parameter = findParameterOptional<ParameterDataType>(
-        parameter_name, parameters, num_components);
+        parameter_name, parameters, num_components, mesh);
 
     if (!parameter)
     {
@@ -116,12 +133,13 @@ template <typename ParameterDataType>
 Parameter<ParameterDataType>& findParameter(
     BaseLib::ConfigTree const& process_config, std::string const& tag,
     std::vector<std::unique_ptr<ParameterBase>> const& parameters,
-    int const num_components)
+    int const num_components, MeshLib::Mesh const* const mesh = nullptr)
 {
     // Find parameter name in process config.
     //! \ogs_file_special
     auto const name = process_config.getConfigParameter<std::string>(tag);
 
-    return findParameter<ParameterDataType>(name, parameters, num_components);
+    return findParameter<ParameterDataType>(name, parameters, num_components,
+                                            mesh);
 }
 }  // namespace ParameterLib
-- 
GitLab