www.mooseframework.org
RichardsSeff1BWsmall.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 // "Broadbridge-White" form of effective saturation for Kn small (P Broadbridge and I White
11 // ``Constant rate rainfall infiltration: A versatile nonlinear model 1. Analytic Solution'', Water
12 // Resources Research 24 (1988) 145-154)
13 //
14 #include "RichardsSeff1BWsmall.h"
15 #include "libmesh/utility.h"
16 
18 
19 template <>
20 InputParameters
22 {
23  InputParameters params = validParams<RichardsSeff>();
24  params.addRequiredRangeCheckedParam<Real>(
25  "Sn",
26  "Sn >= 0",
27  "Low saturation. This must be < Ss, and non-negative. This is BW's "
28  "initial effective saturation, below which effective saturation never goes "
29  "in their simulations/models. If Kn=0 then Sn is the immobile saturation. "
30  "This form of effective saturation is only correct for Kn small.");
31  params.addRangeCheckedParam<Real>(
32  "Ss",
33  1.0,
34  "Ss <= 1",
35  "High saturation. This must be > Sn and <= 1. Effective saturation "
36  "where porepressure = 0. Effective saturation never exceeds this "
37  "value in BW's simulations/models.");
38  params.addRequiredRangeCheckedParam<Real>(
39  "C", "C > 1", "BW's C parameter. Must be > 1. Typical value would be 1.05.");
40  params.addRequiredRangeCheckedParam<Real>("las",
41  "las > 0",
42  "BW's lambda_s parameter multiplied "
43  "by (fluiddensity*gravity). Must be "
44  "> 0. Typical value would be 1E5");
45  params.addClassDescription("Broadbridge-white form of effective saturation for negligable Kn. "
46  "Then porepressure = -las*( (1-th)/th - (1/c)Ln((C-th)/((C-1)th))), "
47  "for th = (Seff - Sn)/(Ss - Sn). A Lambert-W function must be "
48  "evaluated to express Seff in terms of porepressure, which can be "
49  "expensive");
50  return params;
51 }
52 
53 RichardsSeff1BWsmall::RichardsSeff1BWsmall(const InputParameters & parameters)
54  : RichardsSeff(parameters),
55  _sn(getParam<Real>("Sn")),
56  _ss(getParam<Real>("Ss")),
57  _c(getParam<Real>("C")),
58  _las(getParam<Real>("las"))
59 {
60  if (_ss <= _sn)
61  mooseError("In BW effective saturation Sn set to ",
62  _sn,
63  " and Ss set to ",
64  _ss,
65  " but these must obey Ss > Sn");
66 }
67 
68 Real
69 RichardsSeff1BWsmall::LambertW(const Real z) const
70 {
71  /* Lambert W function.
72  Was ~/C/LambertW.c written K M Briggs Keith dot Briggs at bt dot com 97 May 21.
73  Revised KMB 97 Nov 20; 98 Feb 11, Nov 24, Dec 28; 99 Jan 13; 00 Feb 23; 01 Apr 09
74 
75  Computes Lambert W function, principal branch.
76  See LambertW1.c for -1 branch.
77 
78  Returned value W(z) satisfies W(z)*exp(W(z))=z
79  test data...
80  W(1)= 0.5671432904097838730
81  W(2)= 0.8526055020137254914
82  W(20)=2.2050032780240599705
83  To solve (a+b*R)*exp(-c*R)-d=0 for R, use
84  R=-(b*W(-exp(-a*c/b)/b*d*c)+a*c)/b/c
85 
86  Test:
87  gcc -DTESTW LambertW.c -o LambertW -lm && LambertW
88  Library:
89  gcc -O3 -c LambertW.c
90 
91  Modified trially by Andy to use MOOSE things
92  */
93  mooseAssert(z > 0, "LambertW function in RichardsSeff1BWsmall called with negative argument");
94 
95  int i;
96  const Real eps = 4.0e-16; //, em1=0.3678794411714423215955237701614608;
97  Real p, e, t, w;
98 
99  /* Uncomment this stuff is you ever need to call with a negative argument
100  if (z < -em1)
101  mooseError("LambertW: bad argument ", z, "\n");
102 
103  if (0.0 == z)
104  return 0.0;
105  if (z < -em1+1e-4)
106  {
107  // series near -em1 in sqrt(q)
108  Real q=z+em1,r=std::sqrt(q),q2=q*q,q3=q2*q;
109  return
110  -1.0
111  +2.331643981597124203363536062168*r
112  -1.812187885639363490240191647568*q
113  +1.936631114492359755363277457668*r*q
114  -2.353551201881614516821543561516*q2
115  +3.066858901050631912893148922704*r*q2
116  -4.175335600258177138854984177460*q3
117  +5.858023729874774148815053846119*r*q3
118  -8.401032217523977370984161688514*q3*q; // error approx 1e-16
119  }
120  */
121  /* initial approx for iteration... */
122  if (z < 1.0)
123  {
124  /* series near 0 */
125  p = std::sqrt(2.0 * (2.7182818284590452353602874713526625 * z + 1.0));
126  w = -1.0 + p * (1.0 + p * (-0.333333333333333333333 + p * 0.152777777777777777777777));
127  }
128  else
129  w = std::log(z); /* asymptotic */
130  if (z > 3.0)
131  w -= std::log(w); /* useful? */
132  for (i = 0; i < 10; i++)
133  {
134  /* Halley iteration */
135  e = std::exp(w);
136  t = w * e - z;
137  p = w + 1.0;
138  t /= e * p - 0.5 * (p + 1.0) * t / p;
139  w -= t;
140  if (std::abs(t) < eps * (1.0 + std::abs(w)))
141  return w; /* rel-abs error */
142  }
143  /* should never get here */
144  mooseError("LambertW: No convergence at z= ", z, "\n");
145 }
146 
147 Real
148 RichardsSeff1BWsmall::seff(std::vector<const VariableValue *> p, unsigned int qp) const
149 {
150  Real pp = (*p[0])[qp];
151  if (pp >= 0)
152  return 1.0;
153 
154  Real x = (_c - 1.0) * std::exp(_c - 1 - _c * pp / _las);
155  Real th = _c / (1.0 + LambertW(x)); // use branch 0 for positive x
156  return _sn + (_ss - _sn) * th;
157 }
158 
159 void
160 RichardsSeff1BWsmall::dseff(std::vector<const VariableValue *> p,
161  unsigned int qp,
162  std::vector<Real> & result) const
163 {
164  result[0] = 0.0;
165 
166  Real pp = (*p[0])[qp];
167  if (pp >= 0)
168  return;
169 
170  Real x = (_c - 1) * std::exp(_c - 1.0 - _c * pp / _las);
171  Real lamw = LambertW(x);
172  result[0] = Utility::pow<2>(_c) / _las * lamw / Utility::pow<3>(1 + lamw);
173 }
174 
175 void
176 RichardsSeff1BWsmall::d2seff(std::vector<const VariableValue *> p,
177  unsigned int qp,
178  std::vector<std::vector<Real>> & result) const
179 {
180  result[0][0] = 0.0;
181 
182  Real pp = (*p[0])[qp];
183  if (pp >= 0)
184  return;
185 
186  Real x = (_c - 1) * std::exp(_c - 1 - _c * pp / _las);
187  Real lamw = LambertW(x);
188  result[0][0] = -Utility::pow<3>(_c) / Utility::pow<2>(_las) * lamw * (1.0 - 2.0 * lamw) /
189  Utility::pow<5>(1 + lamw);
190 }
RichardsSeff1BWsmall::RichardsSeff1BWsmall
RichardsSeff1BWsmall(const InputParameters &parameters)
Definition: RichardsSeff1BWsmall.C:53
RichardsSeff1BWsmall::LambertW
Real LambertW(const double z) const
LambertW function, returned value satisfies W(z)*exp(W(z))=z.
Definition: RichardsSeff1BWsmall.C:69
validParams< RichardsSeff1BWsmall >
InputParameters validParams< RichardsSeff1BWsmall >()
Definition: RichardsSeff1BWsmall.C:21
RichardsSeff
Base class for effective saturation as a function of porepressure(s) The functions seff,...
Definition: RichardsSeff.h:23
RichardsSeff1BWsmall.h
RichardsSeff1BWsmall::_las
Real _las
BW's lambda_s parameter multiplied by (fluiddensity*gravity)
Definition: RichardsSeff1BWsmall.h:77
RichardsSeff1BWsmall::seff
Real seff(std::vector< const VariableValue * > p, unsigned int qp) const
effective saturation as a function of porepressure
Definition: RichardsSeff1BWsmall.C:148
RichardsSeff1BWsmall::dseff
void dseff(std::vector< const VariableValue * > p, unsigned int qp, std::vector< Real > &result) const
derivative of effective saturation as a function of porepressure
Definition: RichardsSeff1BWsmall.C:160
registerMooseObject
registerMooseObject("RichardsApp", RichardsSeff1BWsmall)
RichardsSeff1BWsmall::d2seff
void d2seff(std::vector< const VariableValue * > p, unsigned int qp, std::vector< std::vector< Real >> &result) const
second derivative of effective saturation as a function of porepressure
Definition: RichardsSeff1BWsmall.C:176
RichardsSeff1BWsmall::_c
Real _c
BW's C parameter.
Definition: RichardsSeff1BWsmall.h:74
RichardsSeff1BWsmall
"Broadbridge-White" form of effective saturation for Kn small as a function of porepressure (not capi...
Definition: RichardsSeff1BWsmall.h:26
RichardsSeff1BWsmall::_sn
Real _sn
BW's initial effective saturation.
Definition: RichardsSeff1BWsmall.h:68
validParams< RichardsSeff >
InputParameters validParams< RichardsSeff >()
Definition: RichardsSeff.C:16
RichardsSeff1BWsmall::_ss
Real _ss
Effective saturation where porepressure = 0.
Definition: RichardsSeff1BWsmall.h:71