diff --git a/MaterialLib/CMakeLists.txt b/MaterialLib/CMakeLists.txt index 60c46c969befbd935b7363f3493e47e78e6107bb..123a4514098c4718a943572ed5176e64aa4dad7c 100644 --- a/MaterialLib/CMakeLists.txt +++ b/MaterialLib/CMakeLists.txt @@ -11,6 +11,7 @@ append_source_files(SOURCES Fluid/Viscosity) append_source_files(SOURCES PorousMedium/Porosity) append_source_files(SOURCES PorousMedium/Storage) append_source_files(SOURCES PorousMedium/Permeability) +append_source_files(SOURCES PorousMedium/UnsaturatedProperty/CapillaryPressure) add_library(MaterialLib ${SOURCES} ) target_link_libraries(MaterialLib diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressureSaturation.cpp b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressureSaturation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d8502961542f3178945bfe619ecff755d65e23a --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressureSaturation.cpp @@ -0,0 +1,54 @@ +/** + * \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 "BrookCoreyCapillaryPressureSaturation.h" + +#include <cmath> + +#include "MathLib/MathTools.h" + +namespace MaterialLib +{ +namespace PorousMedium +{ +double BrookCoreyCapillaryPressureSaturation::getCapillaryPressure( + const double saturation) const +{ + const double S = MathLib::limitValueInInterval( + saturation, _Sr + _minor_offset, _Smax - _minor_offset); + const double Se = (S - _Sr) / (_Smax - _Sr); + const double pc = _pb * std::pow(Se, -1.0 / _mm); + return MathLib::limitValueInInterval(pc, _minor_offset, _Pc_max); +} + +double BrookCoreyCapillaryPressureSaturation::getSaturation( + const double capillary_pressure) const +{ + const double pc = + (capillary_pressure < 0.0) ? _minor_offset : capillary_pressure; + const double Se = std::pow(pc / _pb, -_mm); + const double S = Se * (_Smax - _Sr) + _Sr; + return MathLib::limitValueInInterval(S, _Sr + _minor_offset, + _Smax - _minor_offset); +} + +double BrookCoreyCapillaryPressureSaturation::getdPcdS( + const double saturation) const +{ + const double S = MathLib::limitValueInInterval( + saturation, _Sr + _minor_offset, _Smax - _minor_offset); + 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/BrookCoreyCapillaryPressureSaturation.h b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressureSaturation.h new file mode 100644 index 0000000000000000000000000000000000000000..aeb24f13ab5d866edf8258e164794a3cc6b6b183 --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/BrookCoreyCapillaryPressureSaturation.h @@ -0,0 +1,92 @@ +/** + * \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 BrookCoreyCapillaryPressureSaturation.h + * + * Created on November 1, 2016, 9:45 AM + */ + +#ifndef OGS_BROOK_COREY_CAPILLARY_PRESSURE_SATURATION_H +#define OGS_BROOK_COREY_CAPILLARY_PRESSURE_SATURATION_H + +#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 BrookCoreyCapillaryPressureSaturation final + : public CapillaryPressureSaturation +{ +public: + /** + * @param pb Entry pressure, \f$ p_b \f$ + * @param Sr Residual saturation, \f$ S_r \f$ + * @param Smax Maximum saturation, \f$ S_{\mbox{max}} \f$ + * @param m Exponent, \f$ m \f$ + * @param Pc_max Maximum capillary pressure, \f$ P_c^{\mbox{max}}\f$ + */ + BrookCoreyCapillaryPressureSaturation(const double pb, const double Sr, + const double Smax, const double m, + const double Pc_max) + : _pb(pb), _Sr(Sr), _Smax(Smax), _mm(m), _Pc_max(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 getSaturation(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 + + /** A small number for an offset: + * 1. to set the bound of S, the saturation, such that + * S in [_Sr+_minor_offset, _Smax-_minor_offset] + * 2. to set the bound of Pc, the capillary pressure, such that + * Pc in [_minor_offset, _Pc_max] + */ + const double _minor_offset = std::numeric_limits<double>::epsilon(); +}; + +} // end namespace +} // end namespace +#endif /* OGS_BROOK_COREY_CAPILLARY_PRESSURE_SATURATION_H */ diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CapillaryPressureSaturation.h b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CapillaryPressureSaturation.h new file mode 100644 index 0000000000000000000000000000000000000000..3319c41a5959c24c4e40f33cd122da9961c1ef16 --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CapillaryPressureSaturation.h @@ -0,0 +1,43 @@ +/** + * \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: CapillaryPressureSaturation.h + * + */ + +#ifndef OGS_CAPILLARY_PRESSURE_SATURATION_H +#define OGS_CAPILLARY_PRESSURE_SATURATION_H + +#include <string> + +namespace MaterialLib +{ +namespace PorousMedium +{ +/// Base class of capillary pressure models +class CapillaryPressureSaturation +{ +public: + virtual ~CapillaryPressureSaturation() = default; + + /// Get model name. + virtual std::string getName() const = 0; + + /// Get capillary pressure. + virtual double getCapillaryPressure(const double saturation) const = 0; + + /// Get capillary pressure. + virtual double getSaturation(const double capillary_ressure) const = 0; + + /// Get the derivative of the capillary pressure with respect to saturation + virtual double getdPcdS(const double saturation) const = 0; +}; + +} // end namespace +} // end namespace + +#endif /* OGS_CAPILLARY_PRESSURE_SATURATION_H */ diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.cpp b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6e317e678746e6fd9b07dbc3f9422ce82619928 --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.cpp @@ -0,0 +1,120 @@ +/** + * \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 CreateCapillaryPressureModel.cpp + * + * Created on November 1, 2016, 10:06 AM + */ + +#include "CreateCapillaryPressureModel.h" + +#include "BaseLib/ConfigTree.h" +#include "BaseLib/Error.h" + +#include "CapillaryPressureSaturation.h" +#include "BrookCoreyCapillaryPressureSaturation.h" +#include "VanGenuchtenCapillaryPressureSaturation.h" + +namespace MaterialLib +{ +namespace PorousMedium +{ +/** + \param config ConfigTree object which contains the input data + including <type>BrookCorey</type> + and it has a tag of <capillary_pressure> +*/ +static std::unique_ptr<CapillaryPressureSaturation> createBrookCorey( + BaseLib::ConfigTree const& config) +{ + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__type} + config.checkConfigParameter("type", "BrookCorey"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__BrookCorey__pd} + const double pd = config.getConfigParameter<double>("pd"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__BrookCorey__sr} + const double Sr = config.getConfigParameter<double>("sr"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__BrookCorey__smax} + const double Smax = config.getConfigParameter<double>("smax"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__BrookCorey__m} + const double m = config.getConfigParameter<double>("m"); + if (m < 1.0) // m >= 1 + { + OGS_FATAL( + "The exponent parameter of BrookCorey capillary pressure " + "saturation model, m, must not be smaller than 1"); + } + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__BrookCorey__pc_max} + const double Pc_max = config.getConfigParameter<double>("pc_max"); + + return std::unique_ptr<CapillaryPressureSaturation>( + new BrookCoreyCapillaryPressureSaturation(pd, Sr, Smax, m, Pc_max)); +} + +/** + \param config ConfigTree object which contains the input data + including <type>vanGenuchten</type> + and it has a tag of <capillary_pressure> +*/ +static std::unique_ptr<CapillaryPressureSaturation> createVanGenuchten( + BaseLib::ConfigTree const& config) +{ + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__type} + config.checkConfigParameter("type", "vanGenuchten"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__vanGenuchten__pd} + const double pd = config.getConfigParameter<double>("pd"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__vanGenuchten__sr} + const double Sr = config.getConfigParameter<double>("sr"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__vanGenuchten__smax} + const double Smax = config.getConfigParameter<double>("smax"); + + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__vanGenuchten__m} + const double m = config.getConfigParameter<double>("m"); + if (m > 1.0) // m <= 1 + { + OGS_FATAL( + "The exponent parameter of van Genuchten capillary pressure " + "saturation model, m, must be in an interval of [0, 1]"); + } + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__vanGenuchten__pc_max} + const double Pc_max = config.getConfigParameter<double>("pc_max"); + + return std::unique_ptr<CapillaryPressureSaturation>( + new VanGenuchtenCapillaryPressureSaturation(pd, Sr, Smax, m, Pc_max)); +} + +std::unique_ptr<CapillaryPressureSaturation> createCapillaryPressureModel( + BaseLib::ConfigTree const& config) +{ + //! \ogs_file_param{material_property__porous_medium__porous_medium__capillary_pressure__type} + auto const type = config.peekConfigParameter<std::string>("type"); + + if (type == "BrookCorey") + { + return createBrookCorey(config); + } + else if (type == "vanGenuchten") + { + return createVanGenuchten(config); + } + else + { + OGS_FATAL( + "The capillary pressure models %s are unavailable.\n" + "The available types are: \n\tBrookCorey, \n\tvanGenuchten.\n", + type.data()); + } +} + +} // end namespace +} // end namespace diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.h b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.h new file mode 100644 index 0000000000000000000000000000000000000000..fdedfc56d5b0688d5f68b4597377a59dceed2879 --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.h @@ -0,0 +1,35 @@ +/** + * \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 CreateCapillaryPressureModel.h + * + * Created on November 1, 2016, 10:06 AM + */ + +#ifndef OGS_CREATE_CAPILLARY_PRESSURE_MODEL_H +#define OGS_CREATE_CAPILLARY_PRESSURE_MODEL_H + +#include <memory> + +namespace BaseLib +{ +class ConfigTree; +} + +namespace MaterialLib +{ +namespace PorousMedium +{ +class CapillaryPressureSaturation; +/// Create a capillary pressure model +/// \param config ConfigTree object has a tag of <capillary_pressure> +std::unique_ptr<CapillaryPressureSaturation> createCapillaryPressureModel( + BaseLib::ConfigTree const& config); +} +} // end namespace + +#endif /* OGS_CREATE_CAPILLARY_PRESSURE_MODEL_H */ diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/VanGenuchtenCapillaryPressureSaturation.cpp b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/VanGenuchtenCapillaryPressureSaturation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c8cef0d9226b242fca3f94e58afd7dd8e369a346 --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/VanGenuchtenCapillaryPressureSaturation.cpp @@ -0,0 +1,57 @@ +/** + * \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 VanGenuchtenCapillaryPressureSaturation.cpp + * + * Created on October 28, 2016, 6:05 PM + */ + +#include "VanGenuchtenCapillaryPressureSaturation.h" + +#include <cmath> + +#include "MathLib/MathTools.h" + +namespace MaterialLib +{ +namespace PorousMedium +{ +double VanGenuchtenCapillaryPressureSaturation::getCapillaryPressure( + const double saturation) const +{ + const double S = MathLib::limitValueInInterval( + saturation, _Sr + _minor_offset, _Smax - _minor_offset); + const double Se = (S - _Sr) / (_Smax - _Sr); + const double pc = + _pb * std::pow(std::pow(Se, (-1.0 / _mm)) - 1.0, 1.0 - _mm); + return MathLib::limitValueInInterval(pc, _minor_offset, _Pc_max); +} + +double VanGenuchtenCapillaryPressureSaturation::getSaturation( + const double capillary_pressure) const +{ + const double pc = + (capillary_pressure < 0.0) ? _minor_offset : capillary_pressure; + double Se = std::pow(pc / _pb, 1.0 / (1.0 - _mm)) + 1.0; + Se = std::pow(Se, -_mm); + const double S = Se * (_Smax - _Sr) + _Sr; + return MathLib::limitValueInInterval(S, _Sr + _minor_offset, + _Smax - _minor_offset); +} + +double VanGenuchtenCapillaryPressureSaturation::getdPcdS( + const double saturation) const +{ + const double S = MathLib::limitValueInInterval( + saturation, _Sr + _minor_offset, _Smax - _minor_offset); + const double val1 = std::pow(((S - _Sr) / (_Smax - _Sr)), -1.0 / _mm); + const double val2 = std::pow(val1 - 1.0, -_mm); + return _pb * (_mm - 1.0) * val1 * val2 / (_mm * (S - _Sr)); +} + +} // end namespace +} // end namespace diff --git a/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/VanGenuchtenCapillaryPressureSaturation.h b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/VanGenuchtenCapillaryPressureSaturation.h new file mode 100644 index 0000000000000000000000000000000000000000..1b6fb3c33858b760efb32f684fa73486a13ca448 --- /dev/null +++ b/MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/VanGenuchtenCapillaryPressureSaturation.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 VanGenuchtenCapillaryPressureSaturation.h + * + * Created on October 28, 2016, 6:05 PM + */ + +#ifndef OGS_VAN_GENUCHTEN_CAPILLARY_PRESSURE_SATURATION_H +#define OGS_VAN_GENUCHTEN_CAPILLARY_PRESSURE_SATURATION_H + +#include <limits> + +#include "CapillaryPressureSaturation.h" + +namespace MaterialLib +{ +namespace PorousMedium +{ +/** + * \brief van Genuchten water retention model + * + * \f[p_c=p_b (S_e^{-1/m}-1)^{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]. + * + * If \f$\alpha\f$ instead of \f$p_b\f$ is available, \f$p_b\f$ can be + * calculated + * as + * \f[p_b=\rho g/\alpha\f] + */ +class VanGenuchtenCapillaryPressureSaturation final + : public CapillaryPressureSaturation +{ +public: + /** + * @param pb Entry pressure, \f$ p_b \f$ + * @param Sr Residual saturation, \f$ S_r \f$ + * @param Smax Maximum saturation, \f$ S_{\mbox{max}} \f$ + * @param m Exponent, \f$ m \f$ + * @param Pc_max Maximum capillary pressure, \f$ P_c^{\mbox{max}}\f$ + */ + VanGenuchtenCapillaryPressureSaturation(const double pb, const double Sr, + const double Smax, const double m, + const double Pc_max) + : _pb(pb), _Sr(Sr), _Smax(Smax), _mm(m), _Pc_max(Pc_max) + { + } + + /// Get model name. + std::string getName() const override + { + return "van Genuchten water retention model."; + } + + /// Get capillary pressure. + double getCapillaryPressure(const double saturation) const override; + + /// Get capillary pressure. + double getSaturation(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 + + /** A small number for an offset: + * 1. to set the bound of S, the saturation, such that + * S in [_Sr+_minor_offset, _Smax-_minor_offset] + * 2. to set the bound of Pc, the capillary pressure, such that + * Pc in [_minor_offset, _Pc_max] + */ + const double _minor_offset = std::numeric_limits<double>::epsilon(); +}; + +} // end namespace +} // end namespace +#endif /* OGS_VAN_GENUCHTEN_CAPILLARY_PRESSURE_SATURATION_H */ diff --git a/MathLib/MathTools.h b/MathLib/MathTools.h index e578be54451e0447bbd9aa198bf93c8c2c21140e..5f37210fffa8593d00b5032ff9af43399bdabb25 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_ */ diff --git a/Tests/MaterialLib/TestCapillaryPressureSaturationModel.cpp b/Tests/MaterialLib/TestCapillaryPressureSaturationModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98d9d7c1fe99e2625982085888e5579cc6221acc --- /dev/null +++ b/Tests/MaterialLib/TestCapillaryPressureSaturationModel.cpp @@ -0,0 +1,103 @@ +/** + * \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 TestCapillaryPressureSaturationModel.cpp + * + * Created on November 1, 2016, 11:06 AM + */ + +#include <gtest/gtest.h> + +#include <memory> +#include <vector> + +#include "BaseLib/ConfigTree.h" + +#include "TestTools.h" + +#include "MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CapillaryPressureSaturation.h" +#include "MaterialLib/PorousMedium/UnsaturatedProperty/CapillaryPressure/CreateCapillaryPressureModel.h" + +using namespace MaterialLib; +using namespace MaterialLib::PorousMedium; + +std::unique_ptr<CapillaryPressureSaturation> createCapillaryPressureModel( + const char xml[]) +{ + auto const ptree = readXml(xml); + BaseLib::ConfigTree conf(ptree, "", BaseLib::ConfigTree::onerror, + BaseLib::ConfigTree::onwarning); + auto const& sub_config = conf.getConfigSubtree("capillary_pressure"); + return MaterialLib::PorousMedium::createCapillaryPressureModel(sub_config); +} + +TEST(MaterialPorousMedium, checkBrookCoreyCapillaryPressure) +{ + const char xml[] = + "<capillary_pressure>" + " <type>BrookCorey</type>" + " <pd> 19600.0 </pd> " + " <sr> 0.1 </sr> " + " <smax> 1. </smax> " + " <m> 2 </m> " + " <pc_max> 1.e11 </pc_max> " + "</capillary_pressure>"; + auto const pc_model = createCapillaryPressureModel(xml); + + std::vector<double> S = {0.11, 0.2, 0.3, 0.44, 0.52, 0.6, 0.85}; + // The following expected data are calculated by using OGS5. + std::vector<double> pc = {185941.926417901, 58800, + 41577.878733769, 31888.7772993424, + 28691.4621446869, 26296.1594153975, + 21470.7242542025}; + std::vector<double> dpc_dS = {-9297096.32089506, -294000, + -103944.696834422, -46895.2607343271, + -34156.5025531986, -26296.1594153975, + -14313.8161694683}; + + const double tol_pc = 1.e-6; + for (std::size_t i = 0; i < S.size(); i++) + { + ASSERT_NEAR(S[i], pc_model->getSaturation(pc[i]), 1e-14); + ASSERT_NEAR(pc[i], pc_model->getCapillaryPressure(S[i]), tol_pc); + ASSERT_NEAR(dpc_dS[i], pc_model->getdPcdS(S[i]), tol_pc); + } +} + +// In the following test, the expected results are calculated by using OGS5. +TEST(MaterialPorousMedium, checkVanGenuchtenCapillaryPressure) +{ + // rho=1000, alpha = 0.37, pd=rho*g/alpha + const char xml[] = + "<capillary_pressure>" + " <type>vanGenuchten</type>" + " <pd> 26513.513513513513 </pd> " + " <sr> 0. </sr> " + " <smax> 1. </smax> " + " <m> 0.7 </m> " + " <pc_max> 1.e5 </pc_max> " + "</capillary_pressure>"; + auto const pc_model = createCapillaryPressureModel(xml); + + std::vector<double> S = {0.11, 0.2, 0.3, 0.44, 0.52, 0.6, 0.85}; + // The following expected data are calculated by using OGS5. + std::vector<double> pc = { + 67392.5090996789, 51197.5842770154, 41864.8480636163, 33730.6152475992, + 30210.4060771713, 27091.7425032625, 17726.625235802}; + std::vector<double> dpc_dS = {-274283.722262232, -121944.994573743, + -72852.9253517949, -47580.0457562877, + -41013.0131889419, -37359.7105247455, + -43138.4488851645}; + + const double tol_pc = 1.e-6; + for (std::size_t i = 0; i < S.size(); i++) + { + ASSERT_NEAR(S[i], pc_model->getSaturation(pc[i]), 1e-14); + ASSERT_NEAR(pc[i], pc_model->getCapillaryPressure(S[i]), tol_pc); + ASSERT_NEAR(dpc_dS[i], pc_model->getdPcdS(S[i]), tol_pc); + } +}