From 4facfada7039f59b550a30ed632737135798631e Mon Sep 17 00:00:00 2001
From: Christoph Lehmann <christoph.lehmann@ufz.de>
Date: Tue, 16 Aug 2016 16:48:00 +0200
Subject: [PATCH] [PL] IC essentially is a Parameter

---
 ProcessLib/InitialCondition.cpp | 103 --------------------------------
 ProcessLib/InitialCondition.h   |  77 +++---------------------
 ProcessLib/Process.cpp          |  66 ++++++++++----------
 ProcessLib/Process.h            |   7 ---
 ProcessLib/ProcessVariable.cpp  |  47 +++++----------
 ProcessLib/ProcessVariable.h    |  31 +++-------
 ProcessLib/Utils/ProcessUtils.h |  70 +++++++++++++---------
 7 files changed, 106 insertions(+), 295 deletions(-)
 delete mode 100644 ProcessLib/InitialCondition.cpp

diff --git a/ProcessLib/InitialCondition.cpp b/ProcessLib/InitialCondition.cpp
deleted file mode 100644
index 9eb5bcf5e1e..00000000000
--- a/ProcessLib/InitialCondition.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/**
- * \copyright
- * Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org)
- *            Distributed under a Modified BSD License.
- *              See accompanying file LICENSE.txt or
- *              http://www.opengeosys.org/project/license
- *
- */
-
-#include "InitialCondition.h"
-
-#include <boost/optional.hpp>
-#include <logog/include/logog.hpp>
-
-#include "BaseLib/ConfigTree.h"
-#include "BaseLib/Error.h"
-
-#include "MathLib/Point3d.h"
-#include "MeshLib/Elements/Element.h"
-#include "MeshLib/Mesh.h"
-
-
-namespace ProcessLib
-{
-std::unique_ptr<InitialCondition> createUniformInitialCondition(
-    BaseLib::ConfigTree const& config, int const n_components)
-{
-    //! \ogs_file_param{initial_condition__type}
-    config.checkConfigParameter("type", "Uniform");
-
-    // Optional case for single-component variables where the value can be used.
-    // If the 'value' tag is found, use it and return. Otherwise continue with
-    // then required tag 'values'.
-    if (n_components == 1)
-    {
-        //! \ogs_file_param{initial_condition__Uniform__value}
-        auto const value = config.getConfigParameterOptional<double>("value");
-        if (value)
-        {
-            DBUG("Using value %g for the initial condition.", *value);
-            return std::unique_ptr<InitialCondition>{
-                new UniformInitialCondition{std::vector<double>{*value}}};
-        }
-    }
-
-    std::vector<double> const values =
-        //! \ogs_file_param{initial_condition__Uniform__values}
-        config.getConfigParameter<std::vector<double>>("values");
-    if (values.size() != static_cast<std::size_t>(n_components))
-    {
-        OGS_FATAL(
-            "Number of values for the initial condition is different from the "
-            "number of components.");
-    }
-
-    DBUG("Using following values for the initial condition:");
-    for (double const v : values)
-    {
-        (void)v;    // unused value if building w/o DBUG output.
-        DBUG("\t%g", v);
-    }
-
-    return std::unique_ptr<InitialCondition>{
-        new UniformInitialCondition{values}};
-}
-
-std::unique_ptr<InitialCondition> createMeshPropertyInitialCondition(
-    BaseLib::ConfigTree const& config,
-    MeshLib::Mesh const& mesh,
-    int const n_components)
-{
-    //! \ogs_file_param{initial_condition__type}
-    config.checkConfigParameter("type", "MeshProperty");
-
-    //! \ogs_file_param{initial_condition__MeshProperty__field_name}
-    auto field_name = config.getConfigParameter<std::string>("field_name");
-    DBUG("Using field_name %s", field_name.c_str());
-
-    if (!mesh.getProperties().hasPropertyVector(field_name))
-    {
-        OGS_FATAL("The required property %s does not exists in the mesh.",
-            field_name.c_str());
-    }
-    auto const& property =
-        mesh.getProperties().template getPropertyVector<double>(field_name);
-    if (!property)
-    {
-        OGS_FATAL("The required property %s is not of the requested type.",
-            field_name.c_str());
-    }
-
-    if (property->getNumberOfComponents() !=
-        static_cast<std::size_t>(n_components))
-    {
-        OGS_FATAL("The required property %s has different number of components %d, "
-            "expected %d.",
-            field_name.c_str(), property->getNumberOfComponents(), n_components);
-    }
-    return std::unique_ptr<InitialCondition>(
-        new MeshPropertyInitialCondition(*property));
-}
-
-}  // namespace ProcessLib
diff --git a/ProcessLib/InitialCondition.h b/ProcessLib/InitialCondition.h
index a8e8fc1d2b9..60a89bfcca9 100644
--- a/ProcessLib/InitialCondition.h
+++ b/ProcessLib/InitialCondition.h
@@ -10,89 +10,26 @@
 #ifndef PROCESS_LIB_INITIAL_CONDITION_H_
 #define PROCESS_LIB_INITIAL_CONDITION_H_
 
-#include <cassert>
-#include "BaseLib/ConfigTree.h"
-#include "MeshLib/PropertyVector.h"
-
-namespace BaseLib
-{
-class ConfigTree;
-}
-
-namespace MeshLib
-{
-template <typename>
-class PropertyVector;
-class Mesh;
-}
+#include "Parameter.h"
 
 namespace ProcessLib
 {
-/// The InitialCondition is a base class for spatial distributions of values
-/// defined on mesh nodes.
+// TODO document
 class InitialCondition
 {
 public:
-    virtual ~InitialCondition() = default;
-    virtual double getValue(std::size_t const node_id,
-                            int const component_id) const = 0;
-};
-
-/// Uniform value initial condition
-class UniformInitialCondition : public InitialCondition
-{
-public:
-    explicit UniformInitialCondition(std::vector<double> const& values)
-        : _values(values)
-    {
-    }
-    /// Returns a value for given node and component.
-    virtual double getValue(std::size_t const /*node_id*/,
-                            int const component_id) const override
-    {
-        return _values[component_id];
-    }
-
-private:
-    std::vector<double> const _values;
-};
-
-/// Construct a UniformInitialCondition from configuration.
-/// The initial condition will expect a correct number of components in the
-/// configuration, which should be the same as in the corresponding process
-/// variable.
-std::unique_ptr<InitialCondition> createUniformInitialCondition(
-    BaseLib::ConfigTree const& config, int const n_components);
-
-/// Distribution of values given by a mesh property defined on nodes.
-class MeshPropertyInitialCondition : public InitialCondition
-{
-public:
-    MeshPropertyInitialCondition(
-        MeshLib::PropertyVector<double> const& property)
-        : _property(property)
-    {
-        assert(_property.getMeshItemType() == MeshLib::MeshItemType::Node);
-    }
+    InitialCondition(Parameter<double> const& param) : _param(param) {}
 
-    virtual double getValue(std::size_t const node_id,
-                            int const component_id) const override
+    std::vector<double> const& getTuple(
+            double const t, SpatialPosition const& pos) const
     {
-        return _property.getComponent(node_id, component_id);
+        return _param.getTuple(t, pos);
     }
 
 private:
-    MeshLib::PropertyVector<double> const& _property;
+    Parameter<double> const& _param;
 };
 
-/// Construct a MeshPropertyInitialCondition from configuration.
-/// The initial condition will expect a correct number of components in the
-/// configuration, which should be the same as in the corresponding process
-/// variable.
-std::unique_ptr<InitialCondition> createMeshPropertyInitialCondition(
-    BaseLib::ConfigTree const& config, MeshLib::Mesh const& mesh,
-    int const n_components);
-
 }  // namespace ProcessLib
 
 #endif  // PROCESS_LIB_INITIAL_CONDITION_H_
diff --git a/ProcessLib/Process.cpp b/ProcessLib/Process.cpp
index 4a82d136519..84d1c17eb88 100644
--- a/ProcessLib/Process.cpp
+++ b/ProcessLib/Process.cpp
@@ -72,15 +72,47 @@ void Process::initialize()
 void Process::setInitialConditions(GlobalVector& x)
 {
     DBUG("Set initial conditions.");
+    std::size_t const n_nodes = _mesh.getNumberOfNodes();
+
+    SpatialPosition pos;
+
     for (int variable_id = 0;
          variable_id < static_cast<int>(_process_variables.size());
          ++variable_id)
     {
         ProcessVariable& pv = _process_variables[variable_id];
-        for (int component_id = 0; component_id < pv.getNumberOfComponents();
-             ++component_id)
+        auto const* ic = pv.getInitialCondition();
+        if (!ic)
+            continue;
+
+        auto const num_comp = pv.getNumberOfComponents();
+
+        for (std::size_t node_id = 0; node_id < n_nodes; ++node_id)
         {
-            setInitialConditions(pv, variable_id, component_id, x);
+            MeshLib::Location const l(_mesh.getID(),
+                                      MeshLib::MeshItemType::Node, node_id);
+
+            pos.setNodeID(node_id);
+            auto const& tup = ic->getTuple(0.0, pos); // 0.0 is t!
+
+            for (int comp_id = 0; comp_id < num_comp; ++comp_id)
+            {
+                auto global_index =
+                    std::abs(_local_to_global_index_map->getGlobalIndex(
+                        l, variable_id, comp_id));
+#ifdef USE_PETSC
+                // The global indices of the ghost entries of the global matrix
+                // or the global vectors need to be set as negative values for
+                // equation assembly, however the global indices start from
+                // zero. Therefore, any ghost entry with zero index is assigned
+                // an negative value of the vector size or the matrix dimension.
+                // To assign the initial value for the ghost entries, the
+                // negative indices of the ghost entries are restored to zero.
+                if (global_index == x.size())
+                    global_index = 0;
+#endif
+                x.set(global_index, tup[comp_id]);
+            }
         }
     }
 }
@@ -224,34 +256,6 @@ void Process::finishNamedFunctionsInitialization()
     }
 }
 
-void Process::setInitialConditions(ProcessVariable const& variable,
-                                   int const variable_id,
-                                   int const component_id,
-                                   GlobalVector& x)
-{
-    std::size_t const n_nodes = _mesh.getNumberOfNodes();
-    for (std::size_t node_id = 0; node_id < n_nodes; ++node_id)
-    {
-        MeshLib::Location const l(_mesh.getID(), MeshLib::MeshItemType::Node,
-                                  node_id);
-        auto global_index = std::abs(_local_to_global_index_map->getGlobalIndex(
-            l, variable_id, component_id));
-#ifdef USE_PETSC
-        // The global indices of the ghost entries of the global matrix or
-        // the global vectors need to be set as negative values for equation
-        // assembly, however the global indices start from zero.  Therefore,
-        // any ghost entry with zero index is assigned an negative value of
-        // the vector size or the matrix dimension.  To assign the initial
-        // value for the ghost entries, the negative indices of the ghost
-        // entries are restored to zero.
-        if (global_index == x.size())
-            global_index = 0;
-#endif
-        x.set(global_index,
-              variable.getInitialConditionValue(node_id, component_id));
-    }
-}
-
 void Process::computeSparsityPattern()
 {
     _sparsity_pattern =
diff --git a/ProcessLib/Process.h b/ProcessLib/Process.h
index 2d9595abfdf..7879580d639 100644
--- a/ProcessLib/Process.h
+++ b/ProcessLib/Process.h
@@ -148,13 +148,6 @@ private:
     /// each of the named functions.
     void finishNamedFunctionsInitialization();
 
-    /// Sets the initial condition values in the solution vector x for a given
-    /// process variable and component.
-    void setInitialConditions(ProcessVariable const& variable,
-                              int const variable_id,
-                              int const component_id,
-                              GlobalVector& x);
-
     /// Computes and stores global matrix' sparsity pattern from given
     /// DOF-table.
     void computeSparsityPattern();
diff --git a/ProcessLib/ProcessVariable.cpp b/ProcessLib/ProcessVariable.cpp
index 618c2857534..40d2645adcf 100644
--- a/ProcessLib/ProcessVariable.cpp
+++ b/ProcessLib/ProcessVariable.cpp
@@ -10,48 +10,33 @@
 #include "ProcessVariable.h"
 
 #include <utility>
-
 #include <logog/include/logog.hpp>
 
 #include "GeoLib/GEOObjects.h"
 #include "MeshLib/Mesh.h"
-
-#include "BaseLib/ConfigTree.h"
+#include "ProcessLib/Utils/ProcessUtils.h"
 
 namespace ProcessLib
 {
-ProcessVariable::ProcessVariable(BaseLib::ConfigTree const& config,
-                                 MeshLib::Mesh& mesh,
-                                 GeoLib::GEOObjects const& geometries)
-    :
-    //! \ogs_file_param{prj__process_variables__process_variable__name}
-    _name(config.getConfigParameter<std::string>("name")),
-    _mesh(mesh),
-    //! \ogs_file_param{prj__process_variables__process_variable__components}
-    _n_components(config.getConfigParameter<int>("components"))
+ProcessVariable::ProcessVariable(
+    BaseLib::ConfigTree const& config, MeshLib::Mesh& mesh,
+    GeoLib::GEOObjects const& geometries,
+    std::vector<std::unique_ptr<ParameterBase>> const& parameters)
+    :  //! \ogs_file_param{prj__process_variables__process_variable__name}
+      _name(config.getConfigParameter<std::string>("name")),
+      _mesh(mesh),
+      //! \ogs_file_param{prj__process_variables__process_variable__components}
+      _n_components(config.getConfigParameter<int>("components"))
 {
-    DBUG("Constructing process variable %s", this->_name.c_str());
+    DBUG("Constructing process variable %s", _name.c_str());
 
     // Initial condition
-    //! \ogs_file_param{prj__process_variables__process_variable__initial_condition}
-    if (auto ic_config = config.getConfigSubtreeOptional("initial_condition"))
+    if (auto ic_name =
+            //! \ogs_file_param{prj__process_variables__process_variable__initial_condition}
+            config.getConfigParameterOptional<std::string>("initial_condition"))
     {
-        //! \ogs_file_param{initial_condition__type}
-        auto const type = ic_config->peekConfigParameter<std::string>("type");
-        if (type == "Uniform")
-        {
-            _initial_condition =
-                createUniformInitialCondition(*ic_config, _n_components);
-        }
-        else if (type == "MeshProperty")
-        {
-            _initial_condition =
-                createMeshPropertyInitialCondition(*ic_config, _mesh, _n_components);
-        }
-        else
-        {
-            ERR("Unknown type of the initial condition.");
-        }
+        _initial_condition.reset(new InitialCondition(
+            findParameter<double>(*ic_name, parameters, _n_components)));
     }
     else
     {
diff --git a/ProcessLib/ProcessVariable.h b/ProcessLib/ProcessVariable.h
index 463c9d1a271..ca2828e2acd 100644
--- a/ProcessLib/ProcessVariable.h
+++ b/ProcessLib/ProcessVariable.h
@@ -10,32 +10,14 @@
 #ifndef PROCESS_LIB_PROCESS_VARIABLE_H_
 #define PROCESS_LIB_PROCESS_VARIABLE_H_
 
-
 #include "InitialCondition.h"
 #include "ProcessLib/BoundaryCondition/BoundaryCondition.h"
 #include "ProcessLib/BoundaryCondition/BoundaryConditionConfig.h"
 
-namespace MeshGeoToolsLib
-{
-class MeshNodeSearcher;
-class BoundaryElementsSearcher;
-}
-
 namespace MeshLib
 {
 class Mesh;
-}
-
-namespace GeoLib
-{
-class GEOObjects;
-}
-
-namespace ProcessLib
-{
-class NeumannBcConfig;
-class InitialCondition;
-class UniformDirichletBoundaryCondition;
+template <typename T> class PropertyVector;
 }
 
 namespace ProcessLib
@@ -45,8 +27,10 @@ namespace ProcessLib
 class ProcessVariable
 {
 public:
-    ProcessVariable(BaseLib::ConfigTree const& config, MeshLib::Mesh& mesh,
-                    GeoLib::GEOObjects const& geometries);
+    ProcessVariable(
+        BaseLib::ConfigTree const& config, MeshLib::Mesh& mesh,
+        GeoLib::GEOObjects const& geometries,
+        std::vector<std::unique_ptr<ParameterBase>> const& parameters);
 
     ProcessVariable(ProcessVariable&&);
 
@@ -63,10 +47,9 @@ public:
         const int variable_id,
         unsigned const integration_order);
 
-    double getInitialConditionValue(std::size_t const node_id,
-                                    int const component_id) const
+    InitialCondition const* getInitialCondition() const
     {
-        return _initial_condition->getValue(node_id, component_id);
+        return _initial_condition.get();
     }
 
     // Get or create a property vector for results.
diff --git a/ProcessLib/Utils/ProcessUtils.h b/ProcessLib/Utils/ProcessUtils.h
index de0e73ffacd..57062c652fa 100644
--- a/ProcessLib/Utils/ProcessUtils.h
+++ b/ProcessLib/Utils/ProcessUtils.h
@@ -43,42 +43,26 @@ std::vector<std::reference_wrapper<ProcessVariable>> findProcessVariables(
     std::initializer_list<std::string>
         tag_names);
 
-/// Find a parameter of specific type for a name given in the process
-/// configuration under the tag.
-/// The parameter must have the specified number of components.
-/// In the process config a parameter is referenced by a name. For example it
-/// will be looking for a parameter named "K" in the list of parameters
-/// when the tag is "hydraulic_conductivity":
-/// \code
-///     <process>
-///         ...
-///         <hydraulic_conductivity>K</hydraulic_conductivity>
-///     </process>
-/// \endcode
-/// and return a reference to that parameter. Additionally it checks for the
-/// type of the found parameter.
+/// Find a parameter of specific type for a given name.
+///
+/// \see The documentation of the other findParameter() function.
 template <typename ParameterDataType>
 Parameter<ParameterDataType>& findParameter(
-    BaseLib::ConfigTree const& process_config, std::string const& tag,
+    std::string const& parameter_name,
     std::vector<std::unique_ptr<ParameterBase>> const& parameters,
     unsigned const num_components)
 {
-    // Find parameter name in process config.
-    //! \ogs_file_special
-    auto const name = process_config.getConfigParameter<std::string>(tag);
-
     // Find corresponding parameter by name.
-    auto const parameter_it =
-        std::find_if(parameters.cbegin(), parameters.cend(),
-                     [&name](std::unique_ptr<ParameterBase> const& p) {
-                         return p->name == name;
-                     });
+    auto const parameter_it = std::find_if(
+        parameters.cbegin(), parameters.cend(),
+        [&parameter_name](std::unique_ptr<ParameterBase> const& p) {
+            return p->name == parameter_name;
+        });
 
     if (parameter_it == parameters.end()) {
         OGS_FATAL(
-            "Could not find parameter `%s' in the provided parameters list for "
-            "config tag <%s>.",
-            name.c_str(), tag.c_str());
+            "Could not find parameter `%s' in the provided parameters list.",
+            parameter_name.c_str());
     }
     DBUG("Found parameter `%s'.", (*parameter_it)->name.c_str());
 
@@ -87,18 +71,46 @@ Parameter<ParameterDataType>& findParameter(
         dynamic_cast<Parameter<ParameterDataType>*>(parameter_it->get());
     if (!parameter) {
         OGS_FATAL("The read parameter `%s' is of incompatible type.",
-                  name.c_str());
+                  parameter_name.c_str());
     }
 
     if (parameter->getNumberOfComponents() != num_components) {
         OGS_FATAL(
             "The read parameter `%s' has the wrong number of components (%lu "
             "instead of %u).",
-            name.c_str(), parameter->getNumberOfComponents(), num_components);
+            parameter_name.c_str(), parameter->getNumberOfComponents(),
+            num_components);
     }
 
     return *parameter;
 }
+
+/// Find a parameter of specific type for a name given in the process
+/// configuration under the tag.
+/// The parameter must have the specified number of components.
+/// In the process config a parameter is referenced by a name. For example it
+/// will be looking for a parameter named "K" in the list of parameters
+/// when the tag is "hydraulic_conductivity":
+/// \code
+///     <process>
+///         ...
+///         <hydraulic_conductivity>K</hydraulic_conductivity>
+///     </process>
+/// \endcode
+/// and return a reference to that parameter. Additionally it checks for the
+/// type of the found parameter.
+template <typename ParameterDataType>
+Parameter<ParameterDataType>& findParameter(
+    BaseLib::ConfigTree const& process_config, std::string const& tag,
+    std::vector<std::unique_ptr<ParameterBase>> const& parameters,
+    unsigned const num_components)
+{
+    // 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);
+}
 }  // ProcessLib
 
 #endif  // PROCESSLIB_UTILS_PROCESSUTILS_H
-- 
GitLab