From 4d122ec94acdb8aeaea36673a286eca548f60d82 Mon Sep 17 00:00:00 2001 From: Norbert Grunwald <Norbert.Grunwald@ufz.de> Date: Tue, 20 Aug 2019 17:54:08 +0200 Subject: [PATCH] introduce Brooks&Corey relative permeability to MPL --- MaterialLib/MPL/CreateProperty.cpp | 5 + .../MPL/Properties/RelPermBrooksCorey.cpp | 108 ++++++++++++++++++ .../MPL/Properties/RelPermBrooksCorey.h | 107 +++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 MaterialLib/MPL/Properties/RelPermBrooksCorey.cpp create mode 100644 MaterialLib/MPL/Properties/RelPermBrooksCorey.h diff --git a/MaterialLib/MPL/CreateProperty.cpp b/MaterialLib/MPL/CreateProperty.cpp index 02646eddf90..0c165ece888 100644 --- a/MaterialLib/MPL/CreateProperty.cpp +++ b/MaterialLib/MPL/CreateProperty.cpp @@ -65,6 +65,11 @@ std::unique_ptr<MaterialPropertyLib::Property> createProperty( return createSaturationBrooksCorey(config); } + if (boost::iequals(property_type, "RelPermBrooksCorey")) + { + return createRelPermBrooksCorey(config); + } + // If none of the above property types are found, OGS throws an error. OGS_FATAL("The specified component property type '%s' was not recognized", property_type.c_str()); diff --git a/MaterialLib/MPL/Properties/RelPermBrooksCorey.cpp b/MaterialLib/MPL/Properties/RelPermBrooksCorey.cpp new file mode 100644 index 00000000000..eb760f3a5b7 --- /dev/null +++ b/MaterialLib/MPL/Properties/RelPermBrooksCorey.cpp @@ -0,0 +1,108 @@ +/** + * \author Norbert Grunwald + * \date 02.07.2018 + * \brief + * + * \copyright + * Copyright (c) 2012-2018, 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 "MaterialLib/MPL/Properties/RelPermBrooksCorey.h" +#include "MaterialLib/MPL/Medium.h" + +#include <algorithm> +#include <cmath> + +namespace MaterialPropertyLib +{ +RelPermBrooksCorey::RelPermBrooksCorey( + const double residual_liquid_saturation, + const double residual_gas_saturation, + const double min_relative_permeability_liquid, + const double min_relative_permeability_gas, + const double exponent) + + : _residual_liquid_saturation(residual_liquid_saturation), + _residual_gas_saturation(residual_gas_saturation), + _min_relative_permeability_liquid(min_relative_permeability_liquid), + _min_relative_permeability_gas(min_relative_permeability_gas), + _exponent(exponent){}; + +PropertyDataType RelPermBrooksCorey::value( + VariableArray const& variable_array, + ParameterLib::SpatialPosition const& pos, + double const t) const +{ + /// here, an extra computation of saturation is forced, guaranteeing a + /// correct value. In order to speed up the computing time, saturation could + /// be insertred into the primary variable array after it is computed in the + /// FEM assembly. + auto const s_L = _medium->property(PropertyType::saturation) + .template value<double>(variable_array, pos, t); + + auto const s_L_res = _residual_liquid_saturation; + auto const s_L_max = 1. - _residual_gas_saturation; + auto const k_rel_min_LR = _min_relative_permeability_liquid; + auto const k_rel_min_GR = _min_relative_permeability_gas; + + auto const lambda = _exponent; + + auto const s_eff = (s_L - s_L_res) / (s_L_max - s_L_res); + + if (s_eff >= 1.0) + { + // fully saturated medium + return Pair{{1.0, k_rel_min_GR}}; + } + if (s_eff <= 0.0) + { + // dry medium + return Pair{{k_rel_min_LR, 1.0}}; + } + + auto const k_rel_LR = std::pow(s_eff, (2. + 3. * lambda) / lambda); + auto const k_rel_GR = (1. - s_eff) * (1. - s_eff) * + (1. - std::pow(s_eff, (2. + lambda) / lambda)); + + const Pair kRel = {std::max(k_rel_LR, k_rel_min_LR), + std::max(k_rel_GR, k_rel_min_GR)}; + return kRel; +} +PropertyDataType RelPermBrooksCorey::dValue( + VariableArray const& variable_array, Variable const primary_variable, + ParameterLib::SpatialPosition const& pos, double const t) const +{ + assert((primary_variable == Variable::liquid_saturation) && + "RelPermBrooksCorey::dValue is implemented for " + " derivatives with respect to liquid saturation only."); + auto const s_L = _medium->property(PropertyType::saturation) + .template value<double>(variable_array, pos, t); + + auto const s_L_res = _residual_liquid_saturation; + auto const s_L_max = 1. - _residual_gas_saturation; + auto const lambda = _exponent; + + auto const s_eff = (s_L - s_L_res) / (s_L_max - s_L_res); + auto const d_se_d_sL = 1. / (s_L_max - s_L_res); + + auto const dk_rel_LRdse = + (3 * lambda + 2.) / lambda * std::pow(s_eff, 2. / lambda + 2.); + + auto const dk_rel_LRdsL = dk_rel_LRdse * d_se_d_sL; + + auto const _2L_L = (2. + lambda) / lambda; + auto const dk_rel_GRdse = + -2. * (1 - s_eff) * (1. - std::pow(s_eff, _2L_L)) - + _2L_L * std::pow(s_eff, _2L_L - 1.) * (1. - s_eff) * (1. - s_eff); + auto const dk_rel_GRdsL = dk_rel_GRdse * d_se_d_sL; + + const Pair dkReldsL = {{dk_rel_LRdsL, dk_rel_GRdsL}}; + + return dkReldsL; +} + +} // namespace MaterialPropertyLib diff --git a/MaterialLib/MPL/Properties/RelPermBrooksCorey.h b/MaterialLib/MPL/Properties/RelPermBrooksCorey.h new file mode 100644 index 00000000000..010b5985e00 --- /dev/null +++ b/MaterialLib/MPL/Properties/RelPermBrooksCorey.h @@ -0,0 +1,107 @@ +/** + * \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 "BaseLib/ConfigTree.h" +#include "MaterialLib/MPL/Property.h" + +namespace MaterialPropertyLib +{ +class Medium; +class Phase; +class Component; +/** + * \class RelPermBrooksCorey + * \brief Relative permeability function proposed by Brooks&Corey + * \details This property must be a medium property, it + * computes the permeability reduction due to saturation as function + * of capillary pressure. + */ +class RelPermBrooksCorey final : public Property +{ +private: + Medium* _medium; + const double _residual_liquid_saturation; + const double _residual_gas_saturation; + const double _min_relative_permeability_liquid; + const double _min_relative_permeability_gas; + const double _exponent; + +public: + RelPermBrooksCorey(const double /*residual_liquid_saturation*/, + const double /*residual_gas_saturation*/, + const double /*_min_relative_permeability_liquid*/, + const double /*_min_relative_permeability_gas*/, + const double /*exponent*/ + ); + /// This method assigns a pointer to the meterial object that is the owner + /// of this property + void setScale( + std::variant<Medium*, Phase*, Component*> scale_pointer) override + { + if (std::holds_alternative<Medium*>(scale_pointer)) + { + _medium = std::get<Medium*>(scale_pointer); + } + else + { + OGS_FATAL( + "The property 'RelPermBrooksCorey' is implemented on the " + "'media' scale only."); + } + } + + /// 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; +}; + +inline std::unique_ptr<RelPermBrooksCorey> createRelPermBrooksCorey( + BaseLib::ConfigTree const& config) +{ + // check is reading the parameter, not peeking it... + //! \ogs_file_param{prj__media__medium__properties__property__RelPermBrooksCorey} + // config.checkConfigParameter("type", "RelPermBrooksCorey"); + DBUG("Create RelPermBrooksCorey medium property"); + + auto const residual_liquid_saturation = + //! \ogs_file_param{prj__media__medium__properties__property__RelPermBrooksCorey__residual_liquid_saturation} + config.getConfigParameter<double>("residual_liquid_saturation"); + auto const residual_gas_saturation = + //! \ogs_file_param{prj__media__medium__properties__property__RelPermBrooksCorey__residual_gas_saturation} + config.getConfigParameter<double>("residual_gas_saturation"); + auto const min_relative_permeability_liquid = + //! \ogs_file_param{prj__media__medium__properties__property__RelPermBrooksCorey__k_rel_min_liquid} + config.getConfigParameter<double>("min_relative_permeability_liquid"); + auto const min_relative_permeability_gas = + //! \ogs_file_param{prj__media__medium__properties__property__RelPermBrooksCorey__k_rel_min_gas} + config.getConfigParameter<double>("min_relative_permeability_gas"); + auto const exponent = + //! \ogs_file_param{prj__media__medium__properties__property__RelPermBrooksCorey__lambda} + config.getConfigParameter<double>("lambda"); + + return std::make_unique<RelPermBrooksCorey>( + residual_liquid_saturation, + residual_gas_saturation, + min_relative_permeability_liquid, + min_relative_permeability_gas, + exponent); +} + +} // namespace MaterialPropertyLib -- GitLab