From 3be867a18c380f756e16f2c22660a794d2d3cc6b Mon Sep 17 00:00:00 2001
From: Wenqing Wang <wenqing.wang@ufz.de>
Date: Mon, 23 Mar 2020 15:37:23 +0100
Subject: [PATCH] [MPL] Added a class of
 CapillaryPressureRegularizedVanGenuchten

---
 Documentation/bibliography.bib                |  24 ++++
 ...pillaryPressureRegularizedVanGenuchten.cpp | 136 ++++++++++++++++++
 ...CapillaryPressureRegularizedVanGenuchten.h |  91 ++++++++++++
 3 files changed, 251 insertions(+)
 create mode 100644 MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.cpp
 create mode 100644 MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.h

diff --git a/Documentation/bibliography.bib b/Documentation/bibliography.bib
index b55ba6ca395..0d1386d341c 100644
--- a/Documentation/bibliography.bib
+++ b/Documentation/bibliography.bib
@@ -284,3 +284,27 @@
   doi = "10.1007/978-3-319-68225-9",
   isbn = "978-3-319-68224-2"
 }
+
+@article{marchand2013fully,
+  title={{F}ully coupled generalized hybrid-mixed finite element approximation
+         of two-phase two-component flow in porous media. {Part I}:
+  formulation and properties of the mathematical model},
+  author={Marchand, E and M{\"u}ller, T and Knabner, P},
+  journal={Computational Geosciences},
+  volume={17},
+  number={2},
+  pages={431--442},
+  year={2013},
+  doi = "10.1007/s10596-013-9341-7",
+  publisher={Springer}
+}
+@article{huang2015extending,
+  title={Extending the persistent primary variable algorithm to simulate non-isothermal two-phase two-component flow with phase change phenomena},
+  author={Huang, Yonghui and Kolditz, Olaf and Shao, Haibing},
+  journal={Geothermal Energy},
+  volume={3},
+  number={1},
+  pages={13},
+  year={2015},
+  publisher={Springer}
+}
diff --git a/MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.cpp b/MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.cpp
new file mode 100644
index 00000000000..c0c042bb450
--- /dev/null
+++ b/MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.cpp
@@ -0,0 +1,136 @@
+/**
+ * \file
+ * \copyright
+ * Copyright (c) 2012-2020, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ * Created on April 20, 2020, 9:30 AM
+ */
+
+#include "CapillaryPressureRegularizedVanGenuchten.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "BaseLib/Error.h"
+#include "MaterialLib/MPL/Medium.h"
+#include "MaterialLib/MPL/VariableType.h"
+#include "MaterialLib/MPL/Utils/CheckVanGenuchtenExponentRange.h"
+
+namespace MaterialPropertyLib
+{
+void checkSaturationRange(const double Sl)
+{
+    if (Sl < 0 || Sl > 1)
+    {
+        OGS_FATAL("The saturation of {:e} is out of its range of [0, 1]", Sl);
+    }
+}
+
+CapillaryPressureRegularizedVanGenuchten::
+    CapillaryPressureRegularizedVanGenuchten(
+        double const residual_liquid_saturation,
+        double const maximum_liquid_saturation,
+        double const exponent,
+        double const p_b)
+    : Sg_r_(1.0 - maximum_liquid_saturation),
+      Sg_max_(1.0 - residual_liquid_saturation),
+      m_(exponent),
+      p_b_(p_b),
+      PcBarvGSg_Sg_max_(getPcBarvGSg(Sg_max_)),
+      dPcdSvGBarSg_max_(getdPcdSvGBar(Sg_max_))
+{
+    checkVanGenuchtenExponentRange(m_);
+}
+
+PropertyDataType CapillaryPressureRegularizedVanGenuchten::value(
+    VariableArray const& variable_array,
+    ParameterLib::SpatialPosition const& /*pos*/, double const /*t*/,
+    double const /*dt*/) const
+{
+    const double Sl = std::get<double>(
+        variable_array[static_cast<int>(Variable::liquid_saturation)]);
+
+    checkSaturationRange(Sl);
+
+    double const Sg = 1 - Sl;
+    if (!(Sg < Sg_r_ || Sg > Sg_max_))
+    {
+        return getPcBarvGSg(Sg);
+    }
+    if (Sg < Sg_r_)
+    {
+        return 0.0;
+    }
+
+    return PcBarvGSg_Sg_max_ + dPcdSvGBarSg_max_ * (Sg - Sg_max_);
+}
+
+PropertyDataType CapillaryPressureRegularizedVanGenuchten::dValue(
+    VariableArray const& variable_array, Variable const primary_variable,
+    ParameterLib::SpatialPosition const& /*pos*/, double const /*t*/,
+    double const /*dt*/) const
+{
+    (void)primary_variable;
+    assert(
+        (primary_variable == Variable::liquid_saturation) &&
+        "CapillaryPressureRegularizedVanGenuchten::dValue is implemented for "
+        "derivatives with respect to liquid saturation only.");
+
+    const double Sl = std::get<double>(
+        variable_array[static_cast<int>(Variable::liquid_saturation)]);
+
+    checkSaturationRange(Sl);
+
+    double const Sg = 1 - Sl;
+    if (!(Sg < Sg_r_ || Sg > Sg_max_))
+    {
+        return -getdPcdSvGBar(Sg);
+    }
+    if (Sg < Sg_r_)
+    {
+        return 0.0;
+    }
+
+    return -dPcdSvGBarSg_max_;
+}
+
+double CapillaryPressureRegularizedVanGenuchten::getPcBarvGSg(
+    double const Sg) const
+{
+    double const S_bar = getSBar(Sg);
+    return getPcvGSg(S_bar) - getPcvGSg(Sg_r_ + (Sg_max_ - Sg_r_) * xi_ / 2);
+}
+
+double CapillaryPressureRegularizedVanGenuchten::getSBar(double const Sg) const
+{
+    return Sg_r_ + (1 - xi_) * (Sg - Sg_r_) + 0.5 * xi_ * (Sg_max_ - Sg_r_);
+}
+
+double CapillaryPressureRegularizedVanGenuchten::getPcvGSg(
+    double const Sg) const
+{
+    double const Se = (Sg_max_ - Sg) / (Sg_max_ - Sg_r_);
+    return p_b_ * std::pow(std::pow(Se, (-1.0 / m_)) - 1.0, 1.0 - m_);
+}
+
+double CapillaryPressureRegularizedVanGenuchten::getdPcdSvGBar(
+    double const Sg) const
+{
+    double S_bar = getSBar(Sg);
+    return getdPcdSvG(S_bar) * (1 - xi_);
+}
+
+double CapillaryPressureRegularizedVanGenuchten::getdPcdSvG(
+    const double Sg) const
+{
+    double const n = 1 / (1 - m_);
+    double const Se = (Sg_max_ - Sg) / (Sg_max_ - Sg_r_);
+    auto const temp = std::pow(Se, (-1 / m_));
+    return p_b_ * (1 / (m_ * n)) * (1 / (Sg_max_ - Sg_r_)) *
+           std::pow(temp - 1, (1 / n) - 1) * temp / Se;
+}
+
+}  // namespace MaterialPropertyLib
diff --git a/MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.h b/MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.h
new file mode 100644
index 00000000000..36ed1a0f6b0
--- /dev/null
+++ b/MaterialLib/MPL/Properties/CapillaryPressureSaturation/CapillaryPressureRegularizedVanGenuchten.h
@@ -0,0 +1,91 @@
+/**
+ * \file
+ * \copyright
+ * Copyright (c) 2012-2020, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ * Created on April 20, 2020, 9:30 AM
+ */
+
+#pragma once
+
+#include "MaterialLib/MPL/Property.h"
+
+namespace MaterialPropertyLib
+{
+class Medium;
+
+/**
+ *  \brief This class handles the computation of the capillary pressure,
+ *  \f$ p_c(S_l) \f$, with the
+ * capillary pressure regularization.
+ *
+ *   For the regularized van Genuchten model, please refer to
+ *  \cite huang2015extending.
+ *
+ *   For the van Genuchten capillary pressure mode,
+ *   \sa MaterialPropertyLib::CapillaryPressureVanGenuchten
+ */
+class CapillaryPressureRegularizedVanGenuchten final : public Property
+{
+public:
+    CapillaryPressureRegularizedVanGenuchten(
+        double const residual_liquid_saturation,
+        double const maximum_liquid_saturation,
+        double const exponent,
+        double const p_b);
+
+    void checkScale() const override
+    {
+        if (!std::holds_alternative<Medium*>(scale_))
+        {
+            OGS_FATAL(
+                "The property 'CapillaryPressureRegularizedVanGenuchten' is "
+                "implemented on the 'media' scale only.");
+        }
+    }
+
+    /// \return \f$ p_c(S_l) \f$.
+    PropertyDataType value(VariableArray const& variable_array,
+                           ParameterLib::SpatialPosition const& pos,
+                           double const t,
+                           double const dt) const override;
+
+    /// \return \f$ \frac{\partial p_c(S_l)}{\partial  S_l} \f$
+    PropertyDataType dValue(VariableArray const& variable_array,
+                            Variable const variable,
+                            ParameterLib::SpatialPosition const& pos,
+                            double const t,
+                            double const dt) const override;
+
+private:
+    double const Sg_r_;    ///< Residual saturation of gas phase
+    double const Sg_max_;  ///< Maximum saturation of gas phase
+    double const m_;       ///< Exponent.
+    /// Capillary pressure scaling factor. Sometimes, it is called apparent gas
+    /// entry pressure.
+    double const p_b_;
+    /// parameter in regularized van Genuchten model
+    static constexpr double xi_ = 1e-5;
+
+    double const PcBarvGSg_Sg_max_;
+    double const dPcdSvGBarSg_max_;
+
+    /// Gets regularized capillary pressure via the saturation of the
+    /// non-wetting phase.
+    double getPcBarvGSg(double const Sg) const;
+    /// Gets regularized saturation via the saturation of the non-wetting
+    /// phase.
+    double getSBar(double const Sg) const;
+    /// Gets capillary pressure via the non-wetting phase saturation with the
+    /// original van Genuchten model.
+    double getPcvGSg(double const Sg) const;
+    /// Gets \f$\frac{\partial p_c}{\partial {\bar S}_g }\f$.
+    double getdPcdSvGBar(double const Sg) const;
+    /// Gets \f$\frac{\partial p_c}{\partial {S}_g }\f$.
+    double getdPcdSvG(double const Sg) const;
+};
+
+}  // namespace MaterialPropertyLib
-- 
GitLab