version 3.8
vangenuchten.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
13#ifndef DUMUX_MATERIAL_FLUIDMATRIX_VAN_GENUCHTEN_HH
14#define DUMUX_MATERIAL_FLUIDMATRIX_VAN_GENUCHTEN_HH
15
16#include <cmath>
17#include <algorithm>
18
23
24namespace Dumux::FluidMatrix {
25
35{
36
37public:
51 template<class Scalar>
52 struct Params
53 {
54 Params(Scalar alpha, Scalar n, Scalar l = 0.5)
55 : alpha_(alpha), n_(n), m_(1.0 - 1.0/n), l_(l)
56 {}
57
58 Scalar alpha() const { return alpha_; }
59 void setAlpha(Scalar alpha) { alpha_ = alpha; }
60
61 Scalar m() const { return m_; }
62 void setM(Scalar m) { m_ = m; n_ = 1.0/(1.0 - m); }
63
64 Scalar n() const{ return n_; }
65 void setN(Scalar n){ n_ = n; m_ = 1.0 - 1.0/n; }
66
67 Scalar l() const { return l_; }
68 void setL(Scalar l) { l_ = l; }
69
70 bool operator== (const Params& p) const
71 {
72 return Dune::FloatCmp::eq(alpha_, p.alpha_, 1e-6)
73 && Dune::FloatCmp::eq(n_, p.n_, 1e-6)
74 && Dune::FloatCmp::eq(m_, p.m_, 1e-6)
75 && Dune::FloatCmp::eq(l_, p.l_, 1e-6);
76 }
77
78 private:
79 Scalar alpha_, n_, m_, l_;
80 };
81
86 template<class Scalar = double>
87 static Params<Scalar> makeParams(const std::string& paramGroup)
88 {
89 const auto n = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenN");
90 const auto alpha = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenAlpha");
91 // l is usually chosen to be 0.5 (according to Mualem (1976), WRR)
92 const auto l = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenL", 0.5);
93 return Params<Scalar>(alpha, n, l);
94 }
95
109 template<class Scalar>
110 static Scalar pc(Scalar swe, const Params<Scalar>& params)
111 {
112 using std::pow;
113 using std::clamp;
114
115 swe = clamp(swe, 0.0, 1.0); // the equation below is only defined for 0.0 <= sw <= 1.0
116
117 const Scalar pc = pow(pow(swe, -1.0/params.m()) - 1, 1.0/params.n())/params.alpha();
118 return pc;
119 }
120
135 template<class Scalar>
136 static Scalar swe(Scalar pc, const Params<Scalar>& params)
137 {
138 using std::pow;
139 using std::max;
140
141 pc = max(pc, 0.0); // the equation below is undefined for negative pcs
142
143 const Scalar sw = pow(pow(params.alpha()*pc, params.n()) + 1, -params.m());
144 return sw;
145 }
146
151 template<class Scalar>
152 static Scalar endPointPc(const Params<Scalar>& params)
153 { return 0.0; }
154
171 template<class Scalar>
172 static Scalar dpc_dswe(Scalar swe, const Params<Scalar>& params)
173 {
174 using std::pow;
175 using std::clamp;
176
177 swe = clamp(swe, 0.0, 1.0); // the equation below is only defined for 0.0 <= sw <= 1.0
178
179 const Scalar powSwe = pow(swe, -1/params.m());
180 return - 1.0/params.alpha() * pow(powSwe - 1, 1.0/params.n() - 1)/params.n()
181 * powSwe/swe/params.m();
182 }
183
193 template<class Scalar>
194 static Scalar dswe_dpc(Scalar pc, const Params<Scalar>& params)
195 {
196 using std::pow;
197 using std::max;
198
199 pc = max(pc, 0.0); // the equation below is undefined for negative pcs
200
201 const Scalar powAlphaPc = pow(params.alpha()*pc, params.n());
202 return -pow(powAlphaPc + 1, -params.m()-1)*params.m()*powAlphaPc/pc*params.n();
203 }
204
215 template<class Scalar>
216 static Scalar krw(Scalar swe, const Params<Scalar>& params)
217 {
218 using std::pow;
219 using std::clamp;
220
221 swe = clamp(swe, 0.0, 1.0); // the equation below is only defined for 0.0 <= sw <= 1.0
222
223 const Scalar r = 1.0 - pow(1.0 - pow(swe, 1.0/params.m()), params.m());
224 return pow(swe, params.l())*r*r;
225 }
226
237 template<class Scalar>
238 static Scalar dkrw_dswe(Scalar swe, const Params<Scalar>& params)
239 {
240 using std::pow;
241 using std::clamp;
242
243 swe = clamp(swe, 0.0, 1.0); // the equation below is only defined for 0.0 <= sw <= 1.0
244
245 const Scalar x = 1.0 - pow(swe, 1.0/params.m());
246 const Scalar xToM = pow(x, params.m());
247 return (1.0 - xToM)*pow(swe, params.l()-1) * ( (1.0 - xToM)*params.l() + 2*xToM*(1.0-x)/x );
248 }
249
260 template<class Scalar>
261 static Scalar krn(Scalar swe, const Params<Scalar>& params)
262 {
263 using std::pow;
264 using std::clamp;
265
266 swe = clamp(swe, 0.0, 1.0); // the equation below is only defined for 0.0 <= sw <= 1.0
267
268 return pow(1 - swe, params.l()) * pow(1 - pow(swe, 1.0/params.m()), 2*params.m());
269 }
270
282 template<class Scalar>
283 static Scalar dkrn_dswe(Scalar swe, const Params<Scalar>& params)
284 {
285 using std::pow;
286 using std::clamp;
287
288 swe = clamp(swe, 0.0, 1.0); // the equation below is only defined for 0.0 <= sw <= 1.0
289
290 const auto sne = 1.0 - swe;
291 const auto x = 1.0 - pow(swe, 1.0/params.m());
292 return -pow(sne, params.l()-1.0) * pow(x, 2*params.m() - 1.0) * ( params.l()*x + 2.0*sne/swe*(1.0 - x) );
293 }
294};
295
303template <class Scalar>
305{
306public:
308 template<class S>
309 struct Params
310 {
318 { pcLowSwe_ = pcLowSwe; }
319
323 Scalar pcLowSwe() const
324 { return pcLowSwe_; }
325
330 { pcHighSwe_ = pcHighSwe; }
331
338 Scalar pcHighSwe() const
339 { return pcHighSwe_; }
340
346 { krnLowSwe_ = krnLowSwe; }
347
352 Scalar krnLowSwe() const
353 { return krnLowSwe_; }
354
360 { krwHighSwe_ = krwHighSwe; }
361
366 Scalar krwHighSwe() const
367 { return krwHighSwe_; }
368
369private:
370 S pcLowSwe_ = 0.01;
371 S pcHighSwe_ = 0.99;
372 S krnLowSwe_ = 0.1;
373 S krwHighSwe_ = 0.9;
374 };
375
377 template<class MaterialLaw>
378 void init(const MaterialLaw* m, const std::string& paramGroup)
379 {
380 pcLowSwe_ = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenPcLowSweThreshold", 0.01);
381 pcHighSwe_ = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenPcHighSweThreshold", 0.99);
382 krwHighSwe_ = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenKrwHighSweThreshold", 0.9);
383 krnLowSwe_ = getParamFromGroup<Scalar>(paramGroup, "VanGenuchtenKrnLowSweThreshold", 0.1);
384
385 initPcParameters_(m, pcLowSwe_, pcHighSwe_);
386 initKrParameters_(m, krnLowSwe_, krwHighSwe_);
387 }
388
389 template<class MaterialLaw, class BaseParams, class EffToAbsParams>
390 void init(const MaterialLaw* m, const BaseParams& bp, const EffToAbsParams& etap, const Params<Scalar>& p)
391 {
392 pcLowSwe_ = p.pcLowSwe();
393 pcHighSwe_ = p.pcHighSwe();
394 krwHighSwe_ = p.krwHighSwe();
395 krnLowSwe_ = p.krnLowSwe();
396
397 initPcParameters_(m, pcLowSwe_, pcHighSwe_);
398 initKrParameters_(m, krnLowSwe_, krwHighSwe_);
399 }
400
405 {
406 return Dune::FloatCmp::eq(pcLowSwe_, o.pcLowSwe_, 1e-6)
407 && Dune::FloatCmp::eq(pcHighSwe_, o.pcHighSwe_, 1e-6)
408 && Dune::FloatCmp::eq(krwHighSwe_, o.krwHighSwe_, 1e-6)
409 && Dune::FloatCmp::eq(krnLowSwe_, o.krnLowSwe_, 1e-6);
410 }
411
419 OptionalScalar<Scalar> pc(const Scalar swe) const
420 {
421 // make sure that the capillary pressure observes a derivative
422 // != 0 for 'illegal' saturations. This is favourable for the
423 // newton solver (if the derivative is calculated numerically)
424 // in order to get the saturation moving to the right
425 // direction if it temporarily is in an 'illegal' range.
426 if (swe <= pcLowSwe_)
427 return pcLowSwePcValue_ + pcDerivativeLowSw_*(swe - pcLowSwe_);
428
429 else if (swe >= 1.0)
430 return pcDerivativeHighSweEnd_*(swe - 1.0);
431
432 else if (swe > pcHighSwe_)
433 return pcSpline_.eval(swe);
434
435 else
436 return {}; // no regularization
437 }
438
443 {
444 if (swe <= pcLowSwe_)
445 return pcDerivativeLowSw_;
446
447 else if (swe >= 1.0)
448 return pcDerivativeHighSweEnd_;
449
450 else if (swe > pcHighSwe_)
451 return pcSpline_.evalDerivative(swe);
452
453 else
454 return {}; // no regularization
455 }
456
460 OptionalScalar<Scalar> swe(const Scalar pc) const
461 {
462 if (pc <= 0.0)
463 {
464 if (pcHighSwe_ >= 1.0)
465 return 1.0;
466 else
467 return pc/pcDerivativeHighSweEnd_ + 1.0;
468 }
469
470 // invert spline
471 else if (pc <= pcHighSwePcValue_)
472 return pcSpline_.intersectInterval(pcHighSwe_, 1.0, 0.0, 0.0, 0.0, pc);
473
474 else if (pc >= pcLowSwePcValue_)
475 return (pc - pcLowSwePcValue_)/pcDerivativeLowSw_ + pcLowSwe_;
476
477 else
478 return {}; // no regularization
479 }
480
485 {
486 if (pc <= 0.0)
487 {
488 if (pcHighSwe_ >= 1.0)
489 return 0.0;
490 else
491 return 1.0/pcDerivativeHighSweEnd_;
492 }
493
494 // derivative of the inverse of the function is one over derivative of the function
495 else if (pc <= pcHighSwePcValue_)
496 return 1.0/pcSpline_.evalDerivative(pcSpline_.intersectInterval(pcHighSwe_, 1.0, 0.0, 0.0, 0.0, pc));
497
498 else if (pc >= pcLowSwePcValue_)
499 return 1.0/pcDerivativeLowSw_;
500
501 else
502 return {}; // no regularization
503 }
504
508 OptionalScalar<Scalar> krw(const Scalar swe) const
509 {
510 if (swe <= 0.0)
511 return 0.0;
512 else if (swe >= 1.0)
513 return 1.0;
514 else if (swe >= krwHighSwe_)
515 return krwSpline_.eval(swe);
516 else
517 return {}; // no regularization
518 }
519
524 {
525 if (swe <= 0.0)
526 return 0.0;
527 else if (swe >= 1.0)
528 return 0.0;
529 else if (swe >= krwHighSwe_)
530 return krwSpline_.evalDerivative(swe);
531 else
532 return {}; // no regularization
533 }
534
538 OptionalScalar<Scalar> krn(const Scalar swe) const
539 {
540 if (swe <= 0.0)
541 return 1.0;
542 else if (swe >= 1.0)
543 return 0.0;
544 else if (swe <= krnLowSwe_)
545 return krnSpline_.eval(swe);
546 else
547 return {}; // no regularization
548 }
549
554 {
555 if (swe <= 0.0)
556 return 0.0;
557 else if (swe >= 1.0)
558 return 0.0;
559 else if (swe <= krnLowSwe_)
560 return krnSpline_.evalDerivative(swe);
561 else
562 return {}; // no regularization
563 }
564
565private:
566 template<class MaterialLaw>
567 void initPcParameters_(const MaterialLaw* m, const Scalar lowSwe, const Scalar highSwe)
568 {
569 const auto lowSw = MaterialLaw::EffToAbs::sweToSw(lowSwe, m->effToAbsParams());
570 const auto highSw = MaterialLaw::EffToAbs::sweToSw(highSwe, m->effToAbsParams());
571 const auto dsw_dswe = MaterialLaw::EffToAbs::dsw_dswe(m->effToAbsParams());
572
573 pcDerivativeLowSw_ = m->template dpc_dsw<false>(lowSw)*dsw_dswe;
574
575 pcDerivativeHighSweThreshold_ = m->template dpc_dsw<false>(highSw)*dsw_dswe;
576 pcDerivativeHighSweEnd_ = 2.0*(0.0 - m->template pc<false>(highSw))/(1.0 - highSwe);
577
578 pcLowSwePcValue_ = m->template pc<false>(lowSw);
579 pcHighSwePcValue_ = m->template pc<false>(highSw);
580
581 // Only initialize regularization spline if given parameters are in
582 // the admissible range. When constructing with non-sensible parameters
583 // the spline construction might fail (e.g. highSwe == 1.0)
584 if (highSwe < 1.0)
585 pcSpline_ = Spline<Scalar>(highSwe, 1.0, // x0, x1
586 pcHighSwePcValue_, 0, // y0, y1
587 pcDerivativeHighSweThreshold_, pcDerivativeHighSweEnd_); // m0, m1
588 }
589
590 template<class MaterialLaw>
591 void initKrParameters_(const MaterialLaw* m, const Scalar lowSwe, const Scalar highSwe)
592 {
593 const auto lowSw = MaterialLaw::EffToAbs::sweToSw(lowSwe, m->effToAbsParams());
594 const auto highSw = MaterialLaw::EffToAbs::sweToSw(highSwe, m->effToAbsParams());
595 const auto dsw_dswe = MaterialLaw::EffToAbs::dsw_dswe(m->effToAbsParams());
596
597 const auto krwHighSw = m->template krw<false>(highSw);
598 const auto dkrwHighSw = m->template dkrw_dsw<false>(highSw)*dsw_dswe;
599
600 const auto krnLowSw = m->template krn<false>(lowSw);
601 const auto dkrnLowSw = m->template dkrn_dsw<false>(lowSw)*dsw_dswe;
602
603 if (highSwe < 1.0)
604 krwSpline_ = Spline<Scalar>(highSwe, 1.0, // x0, x1
605 krwHighSw, 1.0, // y0, y1
606 dkrwHighSw, 0.0); // m0, m1
607
608 if (lowSwe > 0.0)
609 krnSpline_ = Spline<Scalar>(0.0, lowSwe, // x0, x1
610 1.0, krnLowSw, // y0, y1
611 0.0, dkrnLowSw); // m0, m1
612 }
613
614 Scalar pcLowSwe_, pcHighSwe_;
615 Scalar pcLowSwePcValue_, pcHighSwePcValue_;
616 Scalar krwHighSwe_, krnLowSwe_;
617 Scalar pcDerivativeLowSw_;
618 Scalar pcDerivativeHighSweThreshold_, pcDerivativeHighSweEnd_;
619
620 Spline<Scalar> pcSpline_;
621 Spline<Scalar> krwSpline_;
622 Spline<Scalar> krnSpline_;
623};
624
629template<typename Scalar = double>
631
636template<typename Scalar = double>
638
639} // end namespace Dumux::FluidMatrix
640
641#endif
This is a policy for 2p material laws how to convert absolute to relative saturations and vice versa.
Definition: efftoabsdefaultpolicy.hh:34
Wrapper class to implement regularized material laws (pc-sw, kr-sw) with a conversion policy between ...
Definition: materiallaw.hh:45
Implementation of the van Genuchten capillary pressure <-> saturation relation, and relative permeabi...
Definition: vangenuchten.hh:35
static Scalar dswe_dpc(Scalar pc, const Params< Scalar > &params)
The partial derivative of the effective saturation to the capillary pressure according to van Genucht...
Definition: vangenuchten.hh:194
static Scalar endPointPc(const Params< Scalar > &params)
The capillary pressure at Swe = 1.0 also called end point capillary pressure.
Definition: vangenuchten.hh:152
static Scalar dkrn_dswe(Scalar swe, const Params< Scalar > &params)
The derivative of the relative permeability for the non-wetting phase in regard to the wetting satura...
Definition: vangenuchten.hh:283
static Scalar swe(Scalar pc, const Params< Scalar > &params)
The saturation-capillary pressure curve according to van Genuchten.
Definition: vangenuchten.hh:136
static Scalar krw(Scalar swe, const Params< Scalar > &params)
The relative permeability for the wetting phase of the medium implied by van Genuchten / Mualem param...
Definition: vangenuchten.hh:216
static Scalar dkrw_dswe(Scalar swe, const Params< Scalar > &params)
The derivative of the relative permeability for the wetting phase in regard to the wetting saturation...
Definition: vangenuchten.hh:238
static Scalar dpc_dswe(Scalar swe, const Params< Scalar > &params)
The partial derivative of the capillary pressure w.r.t. the effective saturation according to van Gen...
Definition: vangenuchten.hh:172
static Scalar pc(Scalar swe, const Params< Scalar > &params)
The capillary pressure-saturation curve according to van Genuchten.
Definition: vangenuchten.hh:110
static Scalar krn(Scalar swe, const Params< Scalar > &params)
The relative permeability for the non-wetting phase of the medium implied by van Genuchten's paramete...
Definition: vangenuchten.hh:261
static Params< Scalar > makeParams(const std::string &paramGroup)
Construct from a subgroup from the global parameter tree.
Definition: vangenuchten.hh:87
A regularization for the VanGenuchten material law.
Definition: vangenuchten.hh:305
bool operator==(const VanGenuchtenRegularization &o) const
Equality comparison with another instance.
Definition: vangenuchten.hh:404
void init(const MaterialLaw *m, const BaseParams &bp, const EffToAbsParams &etap, const Params< Scalar > &p)
Definition: vangenuchten.hh:390
OptionalScalar< Scalar > dpc_dswe(const Scalar swe) const
The regularized partial derivative of the capillary pressure w.r.t. the saturation.
Definition: vangenuchten.hh:442
void init(const MaterialLaw *m, const std::string &paramGroup)
Initialize the spline.
Definition: vangenuchten.hh:378
OptionalScalar< Scalar > krw(const Scalar swe) const
The regularized relative permeability for the wetting phase.
Definition: vangenuchten.hh:508
OptionalScalar< Scalar > krn(const Scalar swe) const
The regularized relative permeability for the non-wetting phase.
Definition: vangenuchten.hh:538
OptionalScalar< Scalar > swe(const Scalar pc) const
The regularized saturation-capillary pressure curve.
Definition: vangenuchten.hh:460
OptionalScalar< Scalar > dkrn_dswe(const Scalar swe) const
The regularized derivative of the relative permeability for the non-wetting phase w....
Definition: vangenuchten.hh:553
OptionalScalar< Scalar > pc(const Scalar swe) const
The regularized capillary pressure-saturation curve regularized part:
Definition: vangenuchten.hh:419
OptionalScalar< Scalar > dswe_dpc(const Scalar pc) const
The regularized partial derivative of the saturation to the capillary pressure.
Definition: vangenuchten.hh:484
OptionalScalar< Scalar > dkrw_dswe(const Scalar swe) const
The regularized derivative of the relative permeability for the wetting phase w.r....
Definition: vangenuchten.hh:523
A 3rd order polynomial spline.
Definition: spline.hh:43
Implementation helper for capillary pressure and relative permeability <-> saturation relations for t...
Definition: brookscorey.hh:23
A wrapper that can either contain a valid Scalar or NaN.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Provides 3rd order polynomial splines.
The parameter type.
Definition: vangenuchten.hh:53
Params(Scalar alpha, Scalar n, Scalar l=0.5)
Definition: vangenuchten.hh:54
Scalar alpha() const
Definition: vangenuchten.hh:58
bool operator==(const Params &p) const
Definition: vangenuchten.hh:70
Scalar l() const
Definition: vangenuchten.hh:67
void setAlpha(Scalar alpha)
Definition: vangenuchten.hh:59
void setL(Scalar l)
Definition: vangenuchten.hh:68
void setM(Scalar m)
Definition: vangenuchten.hh:62
Scalar n() const
Definition: vangenuchten.hh:64
Scalar m() const
Definition: vangenuchten.hh:61
void setN(Scalar n)
Definition: vangenuchten.hh:65
Regularization parameters.
Definition: vangenuchten.hh:310
Scalar krnLowSwe() const
Threshold saturation below which the relative permeability of the non-wetting phase gets regularized.
Definition: vangenuchten.hh:352
void setKrwHighSwe(Scalar krwHighSwe)
Set the threshold saturation above which the relative permeability of the wetting phase gets regulari...
Definition: vangenuchten.hh:359
Scalar krwHighSwe() const
Threshold saturation above which the relative permeability of the wetting phase gets regularized.
Definition: vangenuchten.hh:366
void setKrnLowSwe(Scalar krnLowSwe)
Set the threshold saturation below which the relative permeability of the non-wetting phase gets regu...
Definition: vangenuchten.hh:345
void setPcHighSwe(Scalar pcHighSwe)
Set the threshold saturation above which the capillary pressure is regularized.
Definition: vangenuchten.hh:329
Scalar pcHighSwe() const
Threshold saturation above which the capillary pressure is regularized.
Definition: vangenuchten.hh:338
void setPcLowSwe(Scalar pcLowSwe)
Set the threshold saturation below which the capillary pressure is regularized.
Definition: vangenuchten.hh:317
Scalar pcLowSwe() const
Threshold saturation below which the capillary pressure is regularized.
Definition: vangenuchten.hh:323