From a649f629d5ca9211f8dbcdf2e0f50d6a3b41d30f Mon Sep 17 00:00:00 2001 From: Norbert Grunwald <Norbert.Grunwald@ufz.de> Date: Thu, 15 Aug 2019 08:27:35 +0200 Subject: [PATCH] Brooks-Corey saturation model added to MPL properties --- MaterialLib/MPL/CreateProperty.cpp | 6 + MaterialLib/MPL/Properties/Properties.h | 1 + .../MPL/Properties/SaturationBrooksCorey.cpp | 110 ++++++++++++++++++ .../MPL/Properties/SaturationBrooksCorey.h | 100 ++++++++++++++++ 4 files changed, 217 insertions(+) create mode 100644 MaterialLib/MPL/Properties/SaturationBrooksCorey.cpp create mode 100644 MaterialLib/MPL/Properties/SaturationBrooksCorey.h diff --git a/MaterialLib/MPL/CreateProperty.cpp b/MaterialLib/MPL/CreateProperty.cpp index 4d6eb09f375..7f754fe95ba 100644 --- a/MaterialLib/MPL/CreateProperty.cpp +++ b/MaterialLib/MPL/CreateProperty.cpp @@ -58,6 +58,12 @@ std::unique_ptr<MaterialPropertyLib::Property> createProperty( { return createIdealGasLaw(config); } + + if (boost::iequals(property_type, "SaturationBrooksCorey")) + { + return createSaturationBrooksCorey(config); + } + /* TODO Additional properties go here, for example: if (boost::iequals(property_type, "BilinearTemperaturePressure")) { diff --git a/MaterialLib/MPL/Properties/Properties.h b/MaterialLib/MPL/Properties/Properties.h index f8ca051af51..bd4b40595de 100644 --- a/MaterialLib/MPL/Properties/Properties.h +++ b/MaterialLib/MPL/Properties/Properties.h @@ -17,3 +17,4 @@ #include "IdealGasLaw.h" #include "LinearProperty.h" #include "ParameterProperty.h" +#include "SaturationBrooksCorey.h" diff --git a/MaterialLib/MPL/Properties/SaturationBrooksCorey.cpp b/MaterialLib/MPL/Properties/SaturationBrooksCorey.cpp new file mode 100644 index 00000000000..9f6d0121bcb --- /dev/null +++ b/MaterialLib/MPL/Properties/SaturationBrooksCorey.cpp @@ -0,0 +1,110 @@ +/** + * \file + * \author Norbert Grunwald + * \date 27.06.2018 + * \brief + * + * \copyright + * Copyright (c) 2012-2019, 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 "SaturationBrooksCorey.h" + +#include <algorithm> +#include <cmath> + +#include "MaterialLib/MPL/Medium.h" +#include "MathLib/MathTools.h" + +namespace MaterialPropertyLib +{ +SaturationBrooksCorey::SaturationBrooksCorey( + const double residual_liquid_saturation, + const double residual_gas_saturation, + const double exponent, + const double entry_pressure) + : _residual_liquid_saturation(residual_liquid_saturation), + _residual_gas_saturation(residual_gas_saturation), + _exponent(exponent), + _entry_pressure(entry_pressure){}; + +PropertyDataType SaturationBrooksCorey::value( + VariableArray const& variable_array, + ParameterLib::SpatialPosition const& /*pos*/, + double const /*t*/) const +{ + const double p_cap = std::max( + std::numeric_limits<double>::min(), + std::get<double>( + variable_array[static_cast<int>(Variable::capillary_pressure)])); + + const double s_L_res = _residual_liquid_saturation; + const double s_L_max = 1.0 - _residual_gas_saturation; + const double lambda = _exponent; + const double p_b = _entry_pressure; + + if (p_cap <= p_b) + return s_L_max; + + const double s_eff = std::pow(p_b / p_cap, lambda); + const double s = s_eff * (s_L_max - s_L_res) + s_L_res; + + return MathLib::limitValueInInterval(s, s_L_res + _minor_offset, + s_L_max - _minor_offset); +} + +PropertyDataType SaturationBrooksCorey::dValue( + VariableArray const& variable_array, Variable const primary_variable, + ParameterLib::SpatialPosition const& pos, double const t) const +{ + (void)primary_variable; + assert((primary_variable == Variable::capillary_pressure) && + "SaturationBrooksCorey::dValue is implemented for " + " derivatives with respect to capillary pressure only."); + + const double p_b = _entry_pressure; + const double p_cap = std::max( + p_b, + std::get<double>( + variable_array[static_cast<int>(Variable::capillary_pressure)])); + + auto const s_L = _medium->property(PropertyType::saturation) + .template value<double>(variable_array, pos, t); + + const double lambda = _exponent; + + return -lambda / p_cap * s_L; +} + +PropertyDataType SaturationBrooksCorey::d2Value( + VariableArray const& variable_array, Variable const primary_variable1, + Variable const primary_variable2, ParameterLib::SpatialPosition const& /*pos*/, + double const /*t*/) const +{ + (void)primary_variable1; + (void)primary_variable2; + assert((primary_variable1 == Variable::capillary_pressure) && + (primary_variable2 == Variable::capillary_pressure) && + "SaturationBrooksCorey::d2Value is implemented for " + " derivatives with respect to capillary pressure only."); + + const double p_b = _entry_pressure; + const double p_cap = std::max( + p_b, + std::get<double>( + variable_array[static_cast<int>(Variable::capillary_pressure)])); + + const double s_L_res = _residual_liquid_saturation; + const double s_L_max = 1.0 - _residual_gas_saturation; + + const double lambda = _exponent; + + return lambda * (lambda + 1) * std::pow(p_b / p_cap, lambda) / + (p_cap * p_cap) * (s_L_max - s_L_res); +} + +} // namespace MaterialPropertyLib diff --git a/MaterialLib/MPL/Properties/SaturationBrooksCorey.h b/MaterialLib/MPL/Properties/SaturationBrooksCorey.h new file mode 100644 index 00000000000..2a23e1c77a6 --- /dev/null +++ b/MaterialLib/MPL/Properties/SaturationBrooksCorey.h @@ -0,0 +1,100 @@ +/** + * \file + * \author Norbert Grunwald + * \date 27.06.2018 + * \brief + * + * \copyright + * Copyright (c) 2012-2019, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ +#pragma once + +#include <limits> +#include "BaseLib/ConfigTree.h" +#include "MaterialLib/MPL/Property.h" + +namespace MaterialPropertyLib +{ +class Medium; +class Phase; +class Component; +/** + * \brief A well known soil characteristics function + * \details This property must be a medium property, it + * computes the saturation of the wetting phase as function + * of capillary pressure. + */ +class SaturationBrooksCorey final : public Property +{ +private: + Medium* _medium = nullptr; + const double _residual_liquid_saturation; + const double _residual_gas_saturation; + const double _exponent; + const double _entry_pressure; + +public: + SaturationBrooksCorey(const double residual_liquid_saturation, + const double residual_gas_saturation, + const double exponent, + const double entry_pressure); + + void setScale( + std::variant<Medium*, Phase*, Component*> scale_pointer) override + { + if (!std::holds_alternative<Medium*>(scale_pointer)) + { + OGS_FATAL( + "The property 'SaturationBrooksCorey' is implemented on the " + "'media' scale only."); + } + _medium = std::get<Medium*>(scale_pointer); + } + + /// Those methods override the base class implementations and + /// actually compute and set the property _values and _dValues. + PropertyDataType value(VariableArray const& variable_array, + ParameterLib::SpatialPosition const& /*pos*/, + double const /*t*/) const override; + PropertyDataType dValue(VariableArray const& variable_array, + Variable const variable, + ParameterLib::SpatialPosition const& /*pos*/, + double const /*t*/) const override; + PropertyDataType d2Value(VariableArray const& variable_array, + Variable const variable1, + Variable const variable2, + ParameterLib::SpatialPosition const& /*pos*/, + double const /*t*/) const override; +}; + +inline std::unique_ptr<SaturationBrooksCorey> createSaturationBrooksCorey( + BaseLib::ConfigTree const& config) +{ + // check is reading the parameter, not peeking it... + //! \ogs_file_param{prj__media__medium__properties__property__SaturationBrooksCorey} + // config.checkConfigParameter("type", "SaturationBrooksCorey"); + DBUG("Create SaturationBrooksCorey medium property"); + + auto const residual_liquid_saturation = + //! \ogs_file_param{prj__media__medium__properties__property__SaturationBrooksCorey__residual_liquid_saturation} + config.getConfigParameter<double>("residual_liquid_saturation"); + auto const residual_gas_saturation = + //! \ogs_file_param{prj__media__medium__properties__property__SaturationBrooksCorey__residual_gas_saturation} + config.getConfigParameter<double>("residual_gas_saturation"); + auto const exponent = + //! \ogs_file_param{prj__media__medium__properties__property__SaturationBrooksCorey__lambda} + config.getConfigParameter<double>("lambda"); + auto const entry_pressure = + //! \ogs_file_param{prj__media__medium__properties__property__SaturationBrooksCorey__entry_pressure} + config.getConfigParameter<double>("entry_pressure"); + + return std::make_unique<SaturationBrooksCorey>(residual_liquid_saturation, + residual_gas_saturation, + exponent, entry_pressure); +} + +} // namespace MaterialPropertyLib -- GitLab