OGS
RelPermBrooksCoreyNonwettingPhase.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
5
6#include <algorithm>
7#include <cmath>
8
10
11namespace MaterialPropertyLib
12{
14 std::string name,
15 const double residual_liquid_saturation,
16 const double residual_gas_saturation,
17 const double min_relative_permeability,
18 const double exponent)
21 min_relative_permeability_(min_relative_permeability),
22 exponent_(exponent)
23{
24 name_ = std::move(name);
25
26 if (exponent_ <= 0.)
27 {
29 "RelPermBrooksCoreyNonwettingPhase: exponent 'lambda' must be "
30 "positive, but {} was given.",
31 exponent_);
32 }
34 {
36 "RelPermBrooksCoreyNonwettingPhase: residual_liquid_saturation "
37 "must be non-negative, but {} was given.",
39 }
41 {
43 "RelPermBrooksCoreyNonwettingPhase: residual_gas_saturation must "
44 "be non-negative, but {} was given.",
46 }
48 {
50 "RelPermBrooksCoreyNonwettingPhase: residual_liquid_saturation "
51 "({}) + residual_gas_saturation ({}) must be less than 1 so that "
52 "the effective saturation range is positive.",
54 }
56 {
58 "RelPermBrooksCoreyNonwettingPhase: min_relative_permeability must "
59 "be in [0, 1], but {} was given.",
61 }
62};
63
65 VariableArray const& variable_array,
66 ParameterLib::SpatialPosition const& pos, double const t,
67 double const dt) const
68{
73 auto const s_L = std::visit(
74 [&variable_array, &pos, t, dt](auto&& scale) -> double
75 {
76 return scale->property(PropertyType::saturation)
77 .template value<double>(variable_array, pos, t, dt);
78 },
79 scale_);
80
81 auto const s_L_res = residual_liquid_saturation_;
82 auto const s_L_max = 1. - residual_gas_saturation_;
83
84 auto const lambda = exponent_;
85
86 auto const s_eff = (s_L - s_L_res) / (s_L_max - s_L_res);
87
88 if (s_eff >= 1.0)
89 {
90 // fully saturated medium
92 }
93 if (s_eff <= 0.0)
94 {
95 // dry medium
96 return 1.0;
97 }
98
99 auto const k_rel_GR = (1. - s_eff) * (1. - s_eff) *
100 (1. - std::pow(s_eff, (2. + lambda) / lambda));
101
102 return std::max(k_rel_GR, min_relative_permeability_);
103}
105 VariableArray const& variable_array, Variable const variable,
106 ParameterLib::SpatialPosition const& pos, double const t,
107 double const dt) const
108{
109 if (variable != Variable::liquid_saturation)
110 {
111 OGS_FATAL(
112 "RelPermBrooksCoreyNonwettingPhase::dValue is implemented for "
113 "derivatives with respect to liquid saturation only.");
114 }
119 auto const s_L = std::visit(
120 [&variable_array, &pos, t, dt](auto&& scale) -> double
121 {
122 return scale->property(PropertyType::saturation)
123 .template value<double>(variable_array, pos, t, dt);
124 },
125 scale_);
126
127 auto const s_L_res = residual_liquid_saturation_;
128 auto const s_L_max = 1. - residual_gas_saturation_;
129 auto const lambda = exponent_;
130
131 auto const s_eff = (s_L - s_L_res) / (s_L_max - s_L_res);
132 // Consistency with value(): at the branch points s_eff == 0 (dry, value
133 // clamped to 1.0) and s_eff == 1 (saturated, value clamped to
134 // min_relative_permeability) the value is constant, so the derivative is
135 // zero.
136 if ((s_eff <= 0.) || (s_eff >= 1.))
137 {
138 return 0.0;
139 }
140
141 auto const twoL_L = (2. + lambda) / lambda;
142 auto const s_eff_pow_twoL_L = std::pow(s_eff, twoL_L);
143
144 // Consistency with value(): where the min_relative_permeability clamp is
145 // active, the relative permeability is constant and its derivative is
146 // zero. Returning the unclamped derivative there would feed the Jacobian
147 // a spurious sensitivity over the entire gas-phase invasion band near
148 // full saturation (amplified by up to a factor of
149 // k_rel/min_relative_permeability in terms scaling with dk_rel/k_rel).
150 auto const k_rel_GR = (1. - s_eff) * (1. - s_eff) * (1. - s_eff_pow_twoL_L);
151 if (k_rel_GR <= min_relative_permeability_)
152 {
153 return 0.0;
154 }
155
156 auto const d_se_d_sL = 1. / (s_L_max - s_L_res);
157 auto const dk_rel_GRdse =
158 -2. * (1 - s_eff) * (1. - s_eff_pow_twoL_L) -
159 twoL_L * std::pow(s_eff, twoL_L - 1.) * (1. - s_eff) * (1. - s_eff);
160
161 return dk_rel_GRdse * d_se_d_sL;
162}
163
164} // namespace MaterialPropertyLib
#define OGS_FATAL(...)
Definition Error.h:10
virtual PropertyDataType value() const
std::variant< Medium *, Phase *, Component * > scale_
RelPermBrooksCoreyNonwettingPhase(std::string name, const double residual_liquid_saturation, const double residual_gas_saturation, const double min_relative_permeability, const double exponent)
PropertyDataType dValue(VariableArray const &variable_array, Variable const variable, ParameterLib::SpatialPosition const &pos, double const t, double const dt) const override
std::variant< double, Eigen::Matrix< double, 2, 1 >, Eigen::Matrix< double, 3, 1 >, Eigen::Matrix< double, 2, 2 >, Eigen::Matrix< double, 3, 3 >, Eigen::Matrix< double, 4, 1 >, Eigen::Matrix< double, 6, 1 >, Eigen::MatrixXd > PropertyDataType