From 2c4ea3769d48f9af8c7a4fb39ef7430c8ed6638a Mon Sep 17 00:00:00 2001
From: Wenqing Wang <wenqing.wang@ufz.de>
Date: Tue, 1 Nov 2016 16:31:19 +0100
Subject: [PATCH] [Unsat] Added Brook-Corey capillary pressure model

---
 .../BrookCoreyCapillaryPressure.cpp           | 52 ++++++++++
 .../BrookCoreyCapillaryPressure.h             | 97 +++++++++++++++++++
 MathLib/MathTools.h                           | 10 ++
 3 files changed, 159 insertions(+)
 create mode 100644 MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.cpp
 create mode 100644 MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.h

diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.cpp b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.cpp
new file mode 100644
index 00000000000..d76a57c5c5b
--- /dev/null
+++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.cpp
@@ -0,0 +1,52 @@
+/**
+ * \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
+ *
+ * \file   BrookCoreyCapillaryPressure.cpp
+ *
+ *  Created on November 1, 2016, 9:45 AM
+ */
+
+#include "BrookCoreyCapillaryPressure.h"
+
+#include <cmath>
+
+#include "MathLib/MathTools.h"
+
+namespace MaterialLib
+{
+namespace PorousMedium
+{
+double BrookCoreyCapillaryPressure::getCapillaryPressure(
+    const double saturation) const
+{
+    const double S = MathLib::limitValueInInterval(
+        saturation, _Sr + _perturbation, _Smax - _perturbation);
+    const double Se = (S - _Sr) / (_Smax - _Sr);
+    const double pc = _pb * std::pow(Se, -1.0 / _mm);
+    return MathLib::limitValueInInterval(pc, _perturbation, _Pc_max);
+}
+
+double BrookCoreyCapillaryPressure::getSturation(
+    const double capillary_pressure) const
+{
+    const double pc = (capillary_pressure < 0.0) ? 0.0 : capillary_pressure;
+    const double Se = std::pow(pc / _pb, -_mm);
+    const double S = Se * (_Smax - _Sr) + _Sr;
+    return MathLib::limitValueInInterval(S, _Sr + _perturbation,
+                                         _Smax - _perturbation);
+}
+
+double BrookCoreyCapillaryPressure::getdPcdS(const double saturation) const
+{
+    const double S = MathLib::limitValueInInterval(
+        saturation, _Sr + _perturbation, _Smax - _perturbation);
+    const double val = std::pow(((S - _Sr) / (_Smax - _Sr)), -1.0 / _mm);
+    return (_pb * val) / (_mm * (_Sr - S));
+}
+
+}  // end namespace
+}  // end namespace
diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.h b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.h
new file mode 100644
index 00000000000..5aabe718117
--- /dev/null
+++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressure.h
@@ -0,0 +1,97 @@
+/**
+ * \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
+ *
+ * \file   BrookCoreyCapillaryPressure.h
+ *
+ *  Created on November 1, 2016, 9:45 AM
+ */
+
+#ifndef OGS_BROOK_COREY_CAPILLARY_PRESSURE_H
+#define OGS_BROOK_COREY_CAPILLARY_PRESSURE_H
+
+#include <array>
+#include <limits>  // std::numeric_limits
+
+#include "CapillaryPressureSaturation.h"
+
+namespace MaterialLib
+{
+namespace PorousMedium
+{
+/**
+ *   \brief Brook-Corey capillary pressure saturation model
+ *
+ *   \f[p_c=p_b S_e^{-1/m}\f]
+ *   with
+ *   \f[S_e=\dfrac{S-S_r}{S_{\mbox{max}}-S_r}\f]
+ *   where
+ *    \f{eqnarray*}{
+ *       &p_b&            \mbox{ entry pressure,}\\
+ *       &S_r&            \mbox{ residual saturation,}\\
+ *       &S_{\mbox{max}}& \mbox{ maximum saturation,}\\
+ *       &m(>=1) &        \mbox{ exponent.}\\
+ *    \f}
+ *
+ *    Note:
+ *     \f[m=1/(1-n)\f]
+ */
+class BrookCoreyCapillaryPressure final : public CapillaryPressureSaturation
+{
+public:
+    /** \param parameters An array contains the five parameters:
+     *                     [0] $f p_b $f
+     *                     [1] $f S_r $f
+     *                     [2] $f S_{\mbox{max}} $f
+     *                     [3] $f m $f
+     *                     [4] $f P_c^{\mbox{max}}$f
+     */
+    BrookCoreyCapillaryPressure(std::array<double, 5> const& parameters)
+        : _pb(parameters[0]),
+          _Sr(parameters[1]),
+          _Smax(parameters[2]),
+          _mm(parameters[3]),
+          _Pc_max(parameters[4])
+    {
+    }
+
+    BrookCoreyCapillaryPressure(const BrookCoreyCapillaryPressure& orig)
+        : _pb(orig._pb),
+          _Sr(orig._Sr),
+          _Smax(orig._Smax),
+          _mm(orig._mm),
+          _Pc_max(orig._Pc_max)
+    {
+    }
+
+    /// Get model name.
+    std::string getName() const override
+    {
+        return "Brook-Corey capillary pressure saturation model.";
+    }
+
+    /// Get capillary pressure.
+    double getCapillaryPressure(const double saturation) const override;
+
+    /// Get capillary pressure.
+    double getSturation(const double capillary_pressure) const override;
+
+    /// Get the derivative of the capillary pressure with respect to saturation
+    double getdPcdS(const double saturation) const override;
+
+private:
+    const double _pb;      ///< Entry pressure.
+    const double _Sr;      ///< Residual saturation.
+    const double _Smax;    ///< Maximum saturation.
+    const double _mm;      ///< Exponent (<=1.0), n=1/(1-mm).
+    const double _Pc_max;  ///< Maximum capillaray pressure
+
+    const double _perturbation = std::numeric_limits<double>::epsilon();
+};
+
+}  // end namespace
+}  // end namespace
+#endif /* OGS_BROOK_COREY_CAPILLARY_PRESSURE_H */
diff --git a/MathLib/MathTools.h b/MathLib/MathTools.h
index e578be54451..0ee2bd42ae9 100644
--- a/MathLib/MathTools.h
+++ b/MathLib/MathTools.h
@@ -120,6 +120,16 @@ inline double to_radians(double degrees) {
     return degrees*boost::math::constants::pi<double>()/180.;
 }
 
+template<typename Type> Type limitValueInInterval(const Type variable,
+                                               const Type lower_bound,
+                                               const Type upper_bound)
+{
+    if (variable < lower_bound)
+        return lower_bound;
+    if (variable > upper_bound)
+        return upper_bound;
+    return variable;
+}
 } // namespace
 
 #endif /* MATHTOOLS_H_ */
-- 
GitLab