From 7c890d1cbc64f5c8605e26ceb857e05a7874d3d0 Mon Sep 17 00:00:00 2001
From: Johannes Hommel <johannes.hommel@iws.uni-stuttgart.de>
Date: Mon, 19 Nov 2018 18:23:38 +0100
Subject: [PATCH] Feature/user specified solid params in spatial params

---
 .../nonisothermal/volumevariables.hh          | 229 +++++++++++++++++-
 .../3p3c/implicit/columnxylol/params.input    |  10 +-
 .../3p3c/implicit/columnxylol/problem.hh      |  13 +-
 .../implicit/columnxylol/spatialparams.hh     |  62 ++---
 4 files changed, 262 insertions(+), 52 deletions(-)

diff --git a/dumux/porousmediumflow/nonisothermal/volumevariables.hh b/dumux/porousmediumflow/nonisothermal/volumevariables.hh
index 3c7d08247f..107dec550e 100644
--- a/dumux/porousmediumflow/nonisothermal/volumevariables.hh
+++ b/dumux/porousmediumflow/nonisothermal/volumevariables.hh
@@ -25,10 +25,55 @@
 #ifndef DUMUX_ENERGY_VOLUME_VARIABLES_HH
 #define DUMUX_ENERGY_VOLUME_VARIABLES_HH
 
+#include <type_traits>
+
+#include <dumux/material/solidsystems/inertsolidphase.hh>
 #include <dumux/porousmediumflow/volumevariables.hh>
 
 namespace Dumux {
 
+#ifndef DOXYGEN
+namespace Detail {
+// helper struct detecting if the user-defined spatial params class has user-specified functions
+// for solidHeatCapacity, solidDensity, and solidThermalConductivity.
+// for g++ > 5.3, this can be replaced by a lambda
+template<class E, class SCV, class ES, class SS>
+struct hasSolidHeatCapacity
+{
+    template<class SpatialParams>
+    auto operator()(const SpatialParams& a)
+    -> decltype(a.solidHeatCapacity(std::declval<E>(), std::declval<SCV>(), std::declval<ES>(), std::declval<SS>()))
+    {}
+};
+
+template<class E, class SCV, class ES, class SS>
+struct hasSolidDensity
+{
+    template<class SpatialParams>
+    auto operator()(const SpatialParams& a)
+    -> decltype(a.solidDensity(std::declval<E>(), std::declval<SCV>(), std::declval<ES>(), std::declval<SS>()))
+    {}
+};
+
+template<class E, class SCV, class ES, class SS>
+struct hasSolidThermalConductivity
+{
+    template<class SpatialParams>
+    auto operator()(const SpatialParams& a)
+    -> decltype(a.solidThermalConductivity(std::declval<E>(), std::declval<SCV>(), std::declval<ES>(), std::declval<SS>()))
+    {}
+};
+
+template<class SolidSystem>
+struct isInertSolidPhase : public std::false_type {};
+
+template<class Scalar, class Component>
+struct isInertSolidPhase<SolidSystems::InertSolidPhase<Scalar, Component>> : public std::true_type {};
+
+} // end namespace Detail
+#endif
+
+
 // forward declaration
 template <class IsothermalTraits, class Impl, bool enableEnergyBalance>
 class EnergyVolumeVariablesImplementation;
@@ -55,6 +100,7 @@ public:
     using FluidState = typename IsothermalTraits::FluidState;
     using SolidState = typename IsothermalTraits::SolidState;
     using FluidSystem = typename IsothermalTraits::FluidSystem;
+    using SpatialParams = typename IsothermalTraits::SpatialParams;
 
     //! The temperature is obtained from the problem as a constant for isothermal models
     template<class ElemSol, class Problem, class Element, class Scv>
@@ -163,15 +209,14 @@ public:
                                  const Scv &scv,
                                  SolidState & solidState)
     {
+        Scalar cs = solidHeatCapacity_(elemSol, problem, element, scv, solidState);
+        solidState.setHeatCapacity(cs);
 
-        Scalar solidHeatCapacity = SolidSystem::heatCapacity(solidState);
-        solidState.setHeatCapacity(solidHeatCapacity);
-
-        Scalar solidDensity = SolidSystem::density(solidState);
-        solidState.setDensity(solidDensity);
+        Scalar rhos = solidDensity_(elemSol, problem, element, scv, solidState);
+        solidState.setDensity(rhos);
 
-        Scalar solidThermalConductivity = SolidSystem::thermalConductivity(solidState);
-        solidState.setThermalConductivity(solidThermalConductivity);
+        Scalar lambdas = solidThermalConductivity_(elemSol, problem, element, scv, solidState);
+        solidState.setThermalConductivity(lambdas);
     }
 
     /*!
@@ -250,6 +295,176 @@ protected:
     const Impl &asImp_() const { return *static_cast<const Impl*>(this); }
     Impl &asImp_() { return *static_cast<Impl*>(this); }
 
+private:
+    /*!
+     * It has to be decided if the full solid system / solid state interface is used (general option, but more complicated),
+     * or the simple nonisothermal spatial params interface (simpler but less general).
+     * In the simple nonisothermal spatial params interface the functions solidHeatCapacity, solidDensity, and solidThermalConductivity
+     * in the spatial params overwrite the parameters given in the solid system. This only makes sense in combination
+     * with the simplest solid system InertSolidPhase, and can be used to quickly change parameters in certain domain regions.
+     * For setups with more general solids with several components these functions should not exist. Instead, the solid system
+     * determines the values for solidHeatCapacity, solidDensity, and solidThermalConductivity depending on the given composition.
+     */
+
+    /*!
+     * \name Access functions for the solidsystem / solidstate interface
+     */
+    // \{
+
+    /*!
+     * \brief get the solid heat capacity in an scv
+     * \param elemSol the element solution vector
+     * \param problem the problem to solve
+     * \param element the element (codim-0-entity) the scv belongs to
+     * \param scv the sub control volume
+     * \param solidState the solid state
+     * \note this gets selected if the user uses the solidsystem / solidstate interface
+     */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    auto solidHeatCapacity_(const ElemSol& elemSol,
+                            const Problem& problem,
+                            const Element& element,
+                            const Scv& scv,
+                            const SolidState& solidState)
+    -> typename std::enable_if_t<!decltype(
+            isValid(Detail::hasSolidHeatCapacity<Element, Scv, ElemSol, SolidState>())(problem.spatialParams())
+                                            )::value, Scalar>
+    {
+        return SolidSystem::heatCapacity(solidState);
+    }
+
+    /*!
+     * \brief get the solid density in an scv
+     * \param elemSol the element solution vector
+     * \param problem the problem to solve
+     * \param element the element (codim-0-entity) the scv belongs to
+     * \param scv the sub control volume
+     * \param solidState the solid state
+     * \note this gets selected if the user uses the solidsystem / solidstate interface
+     */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    auto solidDensity_(const ElemSol& elemSol,
+                       const Problem& problem,
+                       const Element& element,
+                       const Scv& scv,
+                       const SolidState& solidState)
+    -> typename std::enable_if_t<!decltype(
+            isValid(Detail::hasSolidDensity<Element, Scv, ElemSol, SolidState>())(problem.spatialParams())
+                                            )::value, Scalar>
+    {
+        return SolidSystem::density(solidState);
+    }
+
+    /*!
+     * \brief get the solid's thermal conductivity in an scv
+     * \param elemSol the element solution vector
+     * \param problem the problem to solve
+     * \param element the element (codim-0-entity) the scv belongs to
+     * \param scv the sub control volume
+     * \param solidState the solid state
+     * \note this gets selected if the user uses the solidsystem / solidstate interface
+     */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    auto solidThermalConductivity_(const ElemSol& elemSol,
+                                   const Problem& problem,
+                                   const Element& element,
+                                   const Scv& scv,
+                                   const SolidState& solidState)
+    -> typename std::enable_if_t<!decltype(
+            isValid(Detail::hasSolidThermalConductivity<Element, Scv, ElemSol, SolidState>())(problem.spatialParams())
+                                            )::value, Scalar>
+    {
+        return SolidSystem::thermalConductivity(solidState);
+    }
+
+    // \}
+
+    /*!
+     * \name Access functions for the simple nonisothermal spatial params interface in
+     *       combination with an InertSolidPhase as solid system
+     */
+    // \{
+
+    /*!
+     * \brief get the solid heat capacity in an scv
+     * \param elemSol the element solution vector
+     * \param problem the problem to solve
+     * \param element the element (codim-0-entity) the scv belongs to
+     * \param scv the sub control volume
+     * \param solidState the solid state
+     * \note this gets selected if the user uses the simple spatial params interface in
+     *       combination with an InertSolidPhase as solid system
+     */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    auto solidHeatCapacity_(const ElemSol& elemSol,
+                            const Problem& problem,
+                            const Element& element,
+                            const Scv& scv,
+                            const SolidState& solidState)
+    -> typename std::enable_if_t<decltype(
+            isValid(Detail::hasSolidHeatCapacity<Element, Scv, ElemSol, SolidState>())(problem.spatialParams())
+                                            )::value, Scalar>
+    {
+        static_assert(Detail::isInertSolidPhase<SolidSystem>::value,
+            "solidHeatCapacity can only be overwritten in the spatial params when the solid system is a simple InertSolidPhase\n"
+            "If you select a proper solid system, the solid heat capacity will be computed as stated in the solid system!");
+        return problem.spatialParams().solidHeatCapacity(element, scv, elemSol, solidState);
+    }
+
+    /*!
+     * \brief get the solid density in an scv
+     * \param elemSol the element solution vector
+     * \param problem the problem to solve
+     * \param element the element (codim-0-entity) the scv belongs to
+     * \param scv the sub control volume
+     * \param solidState the solid state
+     * \note this gets selected if the user uses the simple spatial params interface in
+     *       combination with an InertSolidPhase as solid system
+     */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    auto solidDensity_(const ElemSol& elemSol,
+                       const Problem& problem,
+                       const Element& element,
+                       const Scv& scv,
+                       const SolidState& solidState)
+    -> typename std::enable_if_t<decltype(
+            isValid(Detail::hasSolidDensity<Element, Scv, ElemSol, SolidState>())(problem.spatialParams())
+                                            )::value, Scalar>
+    {
+        static_assert(Detail::isInertSolidPhase<SolidSystem>::value,
+            "solidDensity can only be overwritten in the spatial params when the solid system is a simple InertSolidPhase\n"
+            "If you select a proper solid system, the solid density will be computed as stated in the solid system!");
+        return problem.spatialParams().solidDensity(element, scv, elemSol, solidState);
+    }
+
+    /*!
+     * \brief get the solid's heat capacity in an scv
+     * \param elemSol the element solution vector
+     * \param problem the problem to solve
+     * \param element the element (codim-0-entity) the scv belongs to
+     * \param scv the sub control volume
+     * \param solidState the solid state
+     * \note this gets selected if the user uses the simple spatial params interface in
+     *       combination with an InertSolidPhase as solid system
+     */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    auto solidThermalConductivity_(const ElemSol& elemSol,
+                                   const Problem& problem,
+                                   const Element& element,
+                                   const Scv& scv,
+                                   const SolidState& solidState)
+    -> typename std::enable_if_t<decltype(
+            isValid(Detail::hasSolidThermalConductivity<Element, Scv, ElemSol, SolidState>())(problem.spatialParams())
+                                            )::value, Scalar>
+    {
+        static_assert(Detail::isInertSolidPhase<SolidSystem>::value,
+            "solidThermalConductivity can only be overwritten in the spatial params when the solid system is a simple InertSolidPhase\n"
+            "If you select a proper solid system, the solid thermal conductivity will be computed as stated in the solid system!");
+        return problem.spatialParams().solidThermalConductivity(element, scv, elemSol, solidState);
+    }
+
+    // \}
+
 };
 
 } // end namespace Dumux
diff --git a/test/porousmediumflow/3p3c/implicit/columnxylol/params.input b/test/porousmediumflow/3p3c/implicit/columnxylol/params.input
index f383e20058..f502ce89f7 100644
--- a/test/porousmediumflow/3p3c/implicit/columnxylol/params.input
+++ b/test/porousmediumflow/3p3c/implicit/columnxylol/params.input
@@ -13,12 +13,8 @@ Name = columnxylol # name passed to the output routines
 [Assembly]
 NumericDifferenceMethod = 0 # -1 backward differences, 0: central differences, +1: forward differences
 
-[1.Component]
+[Component]
 SolidDensity = 2650
 SolidThermalConductivity = 2.8
-SolidHeatCapacity = 850
-
-[2.Component]
-SolidDensity = 2650
-SolidThermalConductivity = 2.8
-SolidHeatCapacity = 84000
+SolidHeatCapacityFine = 850
+SolidHeatCapacityCoarse = 84000
diff --git a/test/porousmediumflow/3p3c/implicit/columnxylol/problem.hh b/test/porousmediumflow/3p3c/implicit/columnxylol/problem.hh
index 9769d9117d..22fbccaa6f 100644
--- a/test/porousmediumflow/3p3c/implicit/columnxylol/problem.hh
+++ b/test/porousmediumflow/3p3c/implicit/columnxylol/problem.hh
@@ -28,8 +28,8 @@
 #include <dune/grid/yaspgrid.hh>
 
 #include <dumux/material/fluidsystems/h2oairxylene.hh>
-#include <dumux/material/solidstates/compositionalsolidstate.hh>
-#include <dumux/material/solidsystems/compositionalsolidphase.hh>
+#include <dumux/material/solidstates/inertsolidstate.hh>
+#include <dumux/material/solidsystems/inertsolidphase.hh>
 #include <dumux/material/components/constant.hh>
 
 #include <dumux/discretization/cellcentered/tpfa/properties.hh>
@@ -75,13 +75,10 @@ template<class TypeTag>
 struct SolidSystem<TypeTag, TTag::Column>
 {
     using Scalar = GetPropType<TypeTag, Properties::Scalar>;
-    using ComponentOne = Dumux::Components::Constant<1, Scalar>;
-    using ComponentTwo = Dumux::Components::Constant<2, Scalar>;
-    static constexpr int numInertComponents = 2;
-    using type = SolidSystems::CompositionalSolidPhase<Scalar, ComponentOne, ComponentTwo, numInertComponents>;
+    using Component = Dumux::Components::Constant<1, Scalar>;
+    using type = SolidSystems::InertSolidPhase<Scalar, Component>;
 };
 
-
 //! The two-phase model uses the immiscible fluid state
 template<class TypeTag>
 struct SolidState<TypeTag, TTag::Column>
@@ -90,7 +87,7 @@ private:
     using Scalar = GetPropType<TypeTag, Properties::Scalar>;
     using SolidSystem = GetPropType<TypeTag, Properties::SolidSystem>;
 public:
-    using type = CompositionalSolidState<Scalar, SolidSystem>;
+    using type = InertSolidState<Scalar, SolidSystem>;
 };
 
 // Set the spatial parameters
diff --git a/test/porousmediumflow/3p3c/implicit/columnxylol/spatialparams.hh b/test/porousmediumflow/3p3c/implicit/columnxylol/spatialparams.hh
index 2187574c32..c942f2a062 100644
--- a/test/porousmediumflow/3p3c/implicit/columnxylol/spatialparams.hh
+++ b/test/porousmediumflow/3p3c/implicit/columnxylol/spatialparams.hh
@@ -70,12 +70,11 @@ public:
         coarseK_ = 1.4e-8;
 
         // porosities
-        finePorosity_ = 0.46;
-        coarsePorosity_ = 0.46;
+        porosity_ = 0.46;
 
         // specific heat capacities
-        fineHeatCap_ = 850.;
-        coarseHeatCap_ = 84000.;
+        fineHeatCap_ = getParam<Scalar>("Component.SolidHeatCapacityFine", 850.0);
+        coarseHeatCap_ = getParam<Scalar>("Component.SolidHeatCapacityCoarse", 84000.0);
 
         // residual saturations
         fineMaterialParams_.setSwr(0.12);
@@ -121,31 +120,13 @@ public:
         return coarseK_;
     }
 
-    /*!
-     * \brief Define the porosity \f$[-]\f$ of the spatial parameters
-     *
-     * \param element The current element
-     * \param scv The sub-control volume inside the element.
-     * \param elemSol The solution at the dofs connected to the element.
-     */
-    template<class SolidSystem>
-    Scalar inertVolumeFractionAtPos(const GlobalPosition& globalPos,
-                                    int compIdx) const
+    /*! \brief Define the porosity in [-].
+   *
+   * \param globalPos The global position where we evaluate
+   */
+    Scalar porosityAtPos(const GlobalPosition& globalPos) const
     {
-        if (compIdx == SolidSystem::comp0Idx)
-        {
-            if (isFineMaterial_(globalPos))
-                return 1-finePorosity_;
-            else
-                return 0;
-        }
-        else
-        {
-            if (isFineMaterial_(globalPos))
-                  return 0;
-            else
-                return 1-coarsePorosity_;
-        }
+        return porosity_;
     }
 
     /*!
@@ -168,6 +149,28 @@ public:
             return coarseMaterialParams_;
     }
 
+    /*!
+     * \brief User-defined solid heat capacity.
+     *
+     * \param element The current element
+     * \param scv The sub-control volume inside the element.
+     * \param elemSol The solution at the dofs connected to the element.
+     * \param solidState The solid state
+     * \return the solid heat capacity
+     */
+    template <class ElementSolution, class SolidState>
+    Scalar solidHeatCapacity(const Element& element,
+                             const SubControlVolume& scv,
+                             const ElementSolution& elemSol,
+                             const SolidState& solidState) const
+    {
+        const auto& globalPos = scv.dofPosition();
+        if (isFineMaterial_(globalPos))
+            return fineHeatCap_;
+        else
+            return coarseHeatCap_;
+    }
+
 private:
     bool isFineMaterial_(const GlobalPosition &globalPos) const
     {
@@ -177,8 +180,7 @@ private:
     Scalar fineK_;
     Scalar coarseK_;
 
-    Scalar finePorosity_;
-    Scalar coarsePorosity_;
+    Scalar porosity_;
 
     Scalar fineHeatCap_;
     Scalar coarseHeatCap_;
-- 
GitLab