Loading [MathJax]/extensions/tex2jax.js
Plugins
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
van_genuchten.h
Go to the documentation of this file.
1/*
2 * richards.h
3 *
4 * Created on: 21.12.2019
5 * Author: anaegel
6 */
7
8
9#ifndef RICHARDS__VAN_GENUCHTEN_H_
10#define RICHARDS__VAN_GENUCHTEN_H_
11
12// Standard lib.
13#include <cmath>
14
15// Use ADOL-C for automatic differentiation.
16// #include <adolc/adtl.h>
17
18// Use autodiff for automatic differentiation.
19#include <autodiff/forward/dual.hpp>
20
21
22
23// UG4 lib.
25#include "common/assert.h"
26#include "registry/class.h"
27
28// My libs.
29#include <nlohmann/json.hpp>
30#include "json_basics.hh"
31
32
33
34namespace ug{
35namespace Richards{
36
37typedef autodiff::dual dual;
38
39// const double one = 1.0;
40
41inline void UGCheckValues(const dual &number)
42{
43 if (!std::isfinite(number.val) || std::isnan(number.val))
44 {
45 std::cerr << "WARNING: Invalid value:" << number.val << std::endl;
46 UG_ASSERT(std::isfinite(number.val), "Function is not bounded");
47 }
48
49 if (!std::isfinite(number.grad) || std::isnan(number.grad))
50 {
51 std::cerr << "WARNING: Invalid value:" << number.grad << std::endl;
52 UG_ASSERT(std::isfinite(number.grad), "Derivative is not bounded");
53 }
54
55}
56
57
58
59
60// Parameters for a van Genuchten model.
62{
63 double alpha=1.0;
64
65 double n=2.0;
66 double m=0.5; // default: 1.0 - (1.0/n);}
67
68 double thetaR=0.0; // default: 0.0
69 double thetaS=1.0; // default: 1.0
70
71 double Ksat=1.0; // saturated conductivity K_s (optional)
72
73};
74
75#ifdef UG_JSON
76 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(VanGenuchtenParameters, alpha, n, m, thetaS, thetaR, Ksat);
77#endif
78
79
80#ifdef UG_JSON
82 void CreateJSONMap(const JSONType &array, std::map<std::string, JSONType> &map);
83#endif
84
85/*
86class BrooksCorey
87{
88public:
89 BrooksCorrey()
90 : m_pd(1.0), m_lambda(1.0)
91 {}
92
93 double capillary_pressure(double Sw_eff)
94 {
95 return pow(m_pd*Sw_eff, 1.0/m_lambda);
96 }
97
98
99
100protected:
101 double m_pd; // entry pressure
102 double m_lambda; // ~pore size distribution
103
104
105};
106*/
107
108
109
110
111
113
120template <typename TDerived>
122{
123
124protected:
125 // CRTP functions.
126 const TDerived* me() const
127 { return static_cast<const TDerived*>(this); }
128
129 TDerived* me()
130 { return static_cast<TDerived*>(this); }
131
132 template <typename TFunc>
133 void get_value_and_deriv(TFunc F, double H, double &f, double &df) const
134 {
135 dual h= H;
136 /*f = F(h).val; df = derivative(F, wrt(h), at(h));*/
137 auto [F0, Df0] = derivatives(F, wrt(h), at(h));
138 f = F0; df = Df0;
139 };
140
141public:
143 void get_saturation(double H, double &S, double &dSdH) const
144 {
145 auto sat = [this](dual h){ return me()->Saturation_(h);};
146 get_value_and_deriv(sat, H, S, dSdH);
147 }
148
149 void get_saturations(const double *H, double *S, double *dSdH, size_t n) const
150 {
151 for (size_t i=0; i<n; ++i)
152 { this->get_saturation(H[i], S[i], dSdH[i]); }
153 }
154
156 void get_relative_permeability(double H, double &Kr, double &dKrdH) const
157 {
158 auto perm = [this](dual h){ return me()->RelativePermeability_(h);};
159 get_value_and_deriv(perm, H, Kr, dKrdH);
160 }
161
162 void get_relative_permeabilities(const double *H, double *K, double *dKdH, size_t n) const
163 {
164 for (size_t i=0; i<n; ++i)
165 { this->get_relative_permeability(H[i], K[i], dKdH[i]); }
166 }
167
169 void get_conductivity(double H, double &K, double &dKdH) const
170 {
171 auto cond = [this](dual h){ return me()->Conductivity_(h);};
172 get_value_and_deriv(cond, H, K, dKdH);
173
174 }
175
176 void get_conductivities(const double *H, double *K, double *dKdH, size_t n) const
177 {
178 for (size_t i=0; i<n; ++i)
179 { this->get_conductivity(H[i], K[i], dKdH[i]); }
180 }
181
182
183public: // The following functions can be used from LUA
184
185 // Saturation
186 double Saturation(double H) const
187 {
188 dual h=H;
189 auto func = [this](dual h){ return me()->Saturation_(h);};
190 return func(h).val;
191 }
192 double dSaturation_dH(double H) const
193 {
194 dual h=H;
195 auto func = [this](dual h){ return me()->Saturation_(h);};
196 return derivative(func, wrt(h), at(h));
197 }
198
200 double Conductivity(double H)
201 {
202 dual h=H;
203 auto func = [this](dual h){ return me()->Conductivity_(h);};
204 return func(h).val;
205 }
206
207 double dConductivity_dH(double H)
208 {
209 dual h=H;
210 auto func = [this](dual h){ return me()->Conductivity_(h);};
211 return derivative(func, wrt(h), at(h));
212 }
213
214};
215
216
217
219{
220 static dual ComputeEffectiveSaturation(dual pc, double lambda, double pb)
221 {
222 dual val = pow(pb/pc, lambda);
223 UGCheckValues(val);
224 return val;
225 };
226};
227
228
230template <typename TParameter>
232{
234
235 IParameterizedModel(const TParameter &p) : m_param(p) {}
236
237 void set_parameters(const TParameter &p)
238 { m_param = p; }
239
240 const TParameter& get_parameters() const
241 { return m_param; }
242
243 std::string config_string() const
244 {
245 nlohmann::json jaux = m_param;
246 return jaux.dump();
247 }
248
249 TParameter m_param;
250};
251
252
253/*********************************************
254 * Exponential model.
255 *********************************************/
256
258{
259 double pentry = 1.0;
260 double alpha = 1.0;
261 double beta = 1.0;
262
263 double thetaR = 0.0; // default: 0.0
264 double thetaS = 1.0; // default: 1.0
265
266 double Ksat = 1.0; // saturated conductivity K_s (optional)
267};
268
269#ifdef UG_JSON
270 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ExponentialModelParameters, pentry, alpha, beta, thetaR, thetaS, Ksat)
271#endif
272
273
276 public IRichardsModel<ExponentialModel>,
277 public IParameterizedModel<ExponentialModelParameters>
278{
279public:
283
284 friend base_type;
286
288
289protected:
290
291 // p_c = p_a - p_w : Kapillardruck >=0
292 // psi = p_c / (rho_w * g) : Kapillardruckhoehe >=0
293
295 inline dual EffSaturation_(dual pc) const
296 {
297 const parameter_type &p = this->get_parameters();
298 return exp(-p.alpha * (pc/p.pentry));
299 }
300
302 inline dual Saturation_(dual pc) const
303 {
304 const parameter_type &p = this->get_parameters();
305 UGCheckValues(pc);
306
307 if (pc.val <= 0) return p.thetaS; // Medium is saturated
308 const dual Seff = EffSaturation_(pc); UGCheckValues(Seff);
309 //UG_LOG("seff:" << (pc.val/p.pentry) << " -> " << Seff.val << std::endl);
310 return p.thetaR + (p.thetaS-p.thetaR)*Seff;
311
312 }
313
316 {
317 const parameter_type &p = this->get_parameters();
318 UGCheckValues(pc);
319
320 if (pc.val<= 0) return 1.0;
321 const dual kval = exp(-p.beta * (pc/p.pentry));
322
323 //UG_LOG("k:" << (pc.val/p.pentry) << " -> " << kval.val << std::endl);
324 return kval;
325
326 }
327
328 // Conductivity C:=K_{sat}*k_r
329 inline dual Conductivity_(dual pc) const
330 {
332 }
333
334};
335
336/*********************************************
337 * Van Genuchten-Mualem
338 *********************************************/
339
341{
343
344 static dual ComputeEffectiveSaturation(dual psi_, double alpha, double n, double m)
345 {
346 UGCheckValues(psi_);
347 dual apn = alpha*psi_;
348 UGCheckValues(apn);
349
350 apn = pow(apn, n);
351 UGCheckValues(apn);
352
353 dual val = pow(1.0/(1.0+apn), m);
354 UGCheckValues(val);
355 return val;
356 }
357
359 static dual ComputeEffectiveSaturation(dual psi_, double alpha, double n)
360 { return ComputeEffectiveSaturation(psi_, alpha, n, 1.0-(1.0/n)); }
361};
362
363
364
367: public IRichardsModel<VanGenuchtenModel>, public IParameterizedModel<VanGenuchtenParameters>
368{
369public:
373
374 friend base_type;
376
378
379
380protected:
381
382 // p_c = p_a - p_w : Kapillardruck
383 // psi = p_c / (rho_w * g) : Kapillardruckhoehe
384
386 inline dual EffSaturation_(dual psi_) const
387 {
389 return VanGenuchtenFunctions::ComputeEffectiveSaturation(psi_, p.alpha, p.n, p.m);
390 }
391
393 inline dual Saturation_(dual psi_) const
394 {
396 UGCheckValues(psi_);
397
398 if (psi_ <= 0) return p.thetaS;
399 else
400 {
401 dual Seff = EffSaturation_(psi_);
402 UGCheckValues(Seff);
403 return p.thetaR + (p.thetaS-p.thetaR)*Seff;
404 }
405 }
406
408 inline dual RelativePermeability_(dual psi_) const
409 {
411 UGCheckValues(psi_);
412
413 if (psi_<= 0) return 1.0;
414
415 dual Seff = EffSaturation_(psi_); // Seff -> 1 is dangerous!
416 if (fabs(Seff.val-1.0)<1e-15) return 1.0;
417 UGCheckValues(Seff);
418
419 double m = p.m;
420 dual brackS = 1.0-pow(Seff,1.0/m); // => brackS -> 0.0
421 UGCheckValues(brackS);
422
423 dual auxS = pow(brackS,m); // => this derivative may explode!
424 UGCheckValues(auxS);
425
426 return sqrt(Seff)*(1.0-auxS)*(1.0-auxS); // check!
427 }
428
429 // Conductivity C:=K_{sat}*k_r
430 inline dual Conductivity_(dual psi_) const
431 {
433 return p.Ksat*RelativePermeability_(psi_);
434 }
435
436};
437
438
439/*********************************************
440 * Haverkamp model.
441 *********************************************/
442
443
444
445// Parameters for Haverkamp model.
447{
448 double alpha;
449 double n;
450
451 double beta;
452 double m;
453
454 double thetaR=0.0; // default: 0.0
455 double thetaS=1.0; // default: 1.0
456
457 double Ksat=1.0; // saturated conductivity K_s (optional)
458};
459
460
461
462#ifdef UG_JSON
463
465 void to_json(JSONType& j, const HaverkampParameters& p);
466
468 void from_json(const JSONType& j, HaverkampParameters& p);
469#endif
470
471
472
473
475class HaverkampModel : public IRichardsModel<HaverkampModel>, public IParameterizedModel<HaverkampParameters>
476{
477public:
481
482 friend base_type;
484
487
488#ifdef UG_JSON
489 // TODO: Move to Factory
490 HaverkampModel(const char* json)
491 {
492 nlohmann::json j = nlohmann::json::parse(json);
495 }
496#endif
497
498
499
500protected:
501
502
503 // p_c = p_a - p_w : Kapillardruck
504 // psi = p_c / (rho_w * g) : Kapillardruckhoehe
505
506
509 {
511 if (psi_ <= 0.0) return p.thetaS;
512
513 dual Seff = VanGenuchtenFunctions::ComputeEffectiveSaturation(psi_, p.alpha, p.n, 1.0);
514 return p.thetaR + (p.thetaS-p.thetaR)*Seff;
515
516 }
517
520 {
522 if (psi_<= 0.0) return 1.0;
523
524 return VanGenuchtenFunctions::ComputeEffectiveSaturation(psi_, p.beta, p.m, 1.0);
525 }
526
527 // Conductivity K:=K_{sat}*k_r
529 {
531 return p.Ksat*RelativePermeability_(psi_);
532 }
533
534};
535
536
539 public IParameterizedModel<HaverkampParameters>,
540 public IRichardsModel<GardnerModel>
541{
542public:
546
548
550 void get_saturation(double H, double &S, double &dSdH) const
551 {
552 auto sat = [this](dual h){ return me()->Saturation_(h, m_param);};
553 base_type::get_value_and_deriv(sat, H, S, dSdH);
554 }
555
557 void get_conductivity(double H, double &K, double &dKdH) const
558 {
559 auto cond = [this](dual h){ return Conductivity_(h, m_param);};
560 base_type::get_value_and_deriv(cond, H, K, dKdH);
561 }
562
563 std::string config_string() const;
564
565protected:
566 static double one;
568
569
570 // p_c = p_a - p_w : Kapillardruck
571 // hpc = p_c / (rho_w * g) : Kapillardruckhoehe
572
574
576 { return exp(-p.alpha*psi_); }
577
580 {
581 if (psi_ <= 0) return p.thetaS;
582 else
583 {
584 dual Seff = EffSaturation_(psi_, p);
585 return p.thetaR + (p.thetaS-p.thetaR)*Seff;
586 }
587 }
588
589 // Conductivity K_s*k_r
591 { return p.Ksat* EffSaturation_(psi_, p); }
592
593};
594
595
596
597
598#ifdef UG_JSON
599
600
602template <typename TModel, typename TParameter = typename TModel::parameter_type>
603SmartPtr<TModel> CreateModel(const char *jstring) {
604
606 try
607 {
608 nlohmann::json j = nlohmann::json::parse(jstring);
609 TParameter p = j.get<TParameter>();
610 inst = make_sp(new TModel(p));
611 }
612 catch (...)
613 {
614 UG_THROW ("Construction failed: " << jstring);
615 }
616 return inst;
617};
618
619
620
622SmartPtr<VanGenuchtenModel> CreateVanGenuchtenModel(const char *json);
623
624
626struct RichardsModelFactory {
627 SmartPtr<ExponentialModel> create_exponential(const char *json);
628 SmartPtr<VanGenuchtenModel> create_van_genuchten(const char *json);
629 SmartPtr<HaverkampModel> create_haverkamp(const char *json);
630};
631
632#endif
633
634
635
636
637}
638
639
640#ifdef UG_JSON
641 template <> struct is_json_constructible<typename Richards::ExponentialModelParameters> { const static bool value = true;};
642#endif
643}
644
645
646
647#ifdef UG_JSON
648// Finally, we need to define how to construct from JSON.
649namespace nlohmann {
650
651 template <>
652 struct adl_serializer<ug::Richards::VanGenuchtenModel>
653 {
654 static ug::Richards::VanGenuchtenModel from_json(const json& j)
655 { return j.get<typename ug::Richards::VanGenuchtenParameters>(); }; // initialize from model }
656
657 static void to_json(json& j, typename ug::Richards::VanGenuchtenModel m)
658 { j = m.get_parameters();}
659 };
660};
661#endif
662
663#endif /* RICHARDS__VAN_GENUCHTEN_H_ */
parameterString p
Definition Biogas.lua:1
Implement a simple exponential model.
Definition van_genuchten.h:278
ExponentialModelParameters parameter_type
Definition van_genuchten.h:281
dual Conductivity_(dual pc) const
Definition van_genuchten.h:329
dual RelativePermeability_(dual pc) const
Relative permeability: $0 \le k_r \le 1$.
Definition van_genuchten.h:315
dual Saturation_(dual pc) const
Rescaled Saturation: $$ S:=\theta_r+ (\theta_s - \theta_r) * \hat S$$.
Definition van_genuchten.h:302
friend parameterized_model_type
Definition van_genuchten.h:285
IParameterizedModel< ExponentialModelParameters > parameterized_model_type
Definition van_genuchten.h:282
ExponentialModel(const parameter_type &p)
Definition van_genuchten.h:287
dual EffSaturation_(dual pc) const
Effective saturation: $0 \le \hat S \le 1$.
Definition van_genuchten.h:295
friend base_type
Definition van_genuchten.h:284
IRichardsModel< ExponentialModel > base_type
Definition van_genuchten.h:280
Implements a van Genuchten model.
Definition van_genuchten.h:541
GardnerModel(const VanGenuchtenParameters &p)
Definition van_genuchten.h:547
IRichardsModel< GardnerModel > base_type
Definition van_genuchten.h:543
std::string config_string() const
VanGenuchtenParameters parameter_type
Definition van_genuchten.h:545
IParameterizedModel< HaverkampParameters > parameterized_model_type
Definition van_genuchten.h:544
void get_conductivity(double H, double &K, double &dKdH) const
Conductivity K.
Definition van_genuchten.h:557
static dual Conductivity_(dual psi_, const VanGenuchtenParameters &p)
Definition van_genuchten.h:590
VanGenuchtenParameters m_param
Definition van_genuchten.h:567
static dual Saturation_(dual psi_, const VanGenuchtenParameters &p)
Rescaled Saturation.
Definition van_genuchten.h:579
void get_saturation(double H, double &S, double &dSdH) const
Saturation.
Definition van_genuchten.h:550
static dual EffSaturation_(dual psi_, const VanGenuchtenParameters &p)
Normalisierter Wassergehalt (reduzierte Sättigung):
Definition van_genuchten.h:575
static double one
Definition van_genuchten.h:566
Implements a Haverkamp model.
Definition van_genuchten.h:476
friend base_type
Definition van_genuchten.h:482
IRichardsModel< HaverkampModel > base_type
Definition van_genuchten.h:478
HaverkampParameters parameter_type
Definition van_genuchten.h:480
dual Saturation_(dual psi_) const
Rescaled Saturation $$ S:=\theta_r+ (\theta_s - \theta_r) * \hat S $$.
Definition van_genuchten.h:508
IParameterizedModel< HaverkampParameters > parameterized_model_type
Definition van_genuchten.h:479
HaverkampModel(const parameter_type &p)
Definition van_genuchten.h:485
friend parameterized_model_type
Definition van_genuchten.h:483
dual Conductivity_(dual psi_) const
Definition van_genuchten.h:528
dual RelativePermeability_(dual psi_) const
Relative permeability $0 \le k_r \le 1$.
Definition van_genuchten.h:519
This is the interface for a Richards-type model. All derived classes use CRTP for evaluation.
Definition van_genuchten.h:122
double Conductivity(double H)
Conductivity K = Ks*kr.
Definition van_genuchten.h:200
void get_relative_permeability(double H, double &Kr, double &dKrdH) const
Calls RelativePermeability_.
Definition van_genuchten.h:156
void get_value_and_deriv(TFunc F, double H, double &f, double &df) const
Definition van_genuchten.h:133
const TDerived * me() const
Definition van_genuchten.h:126
void get_saturations(const double *H, double *S, double *dSdH, size_t n) const
Definition van_genuchten.h:149
double Saturation(double H) const
Definition van_genuchten.h:186
void get_conductivities(const double *H, double *K, double *dKdH, size_t n) const
Definition van_genuchten.h:176
TDerived * me()
Definition van_genuchten.h:129
double dConductivity_dH(double H)
Definition van_genuchten.h:207
void get_conductivity(double H, double &K, double &dKdH) const
Calls Conductivity_.
Definition van_genuchten.h:169
double dSaturation_dH(double H) const
Definition van_genuchten.h:192
void get_relative_permeabilities(const double *H, double *K, double *dKdH, size_t n) const
Definition van_genuchten.h:162
void get_saturation(double H, double &S, double &dSdH) const
Calls Saturation_.
Definition van_genuchten.h:143
Implements a van Genuchten-Mualem model.
Definition van_genuchten.h:368
dual RelativePermeability_(dual psi_) const
Relative permeability: $0 \le k_r \le 1$.
Definition van_genuchten.h:408
VanGenuchtenModel(const parameter_type &p)
Definition van_genuchten.h:377
VanGenuchtenParameters parameter_type
Definition van_genuchten.h:372
friend parameterized_model_type
Definition van_genuchten.h:375
dual Conductivity_(dual psi_) const
Definition van_genuchten.h:430
dual Saturation_(dual psi_) const
Rescaled Saturation: $$ S:=\theta_r+ (\theta_s - \theta_r) * \hat S$$.
Definition van_genuchten.h:393
dual EffSaturation_(dual psi_) const
Effective saturation: $0 \le \hat S \le 1$.
Definition van_genuchten.h:386
IParameterizedModel< VanGenuchtenParameters > parameterized_model_type
Definition van_genuchten.h:371
friend base_type
Definition van_genuchten.h:374
IRichardsModel< VanGenuchtenModel > base_type
Definition van_genuchten.h:370
const NullSmartPtr SPNULL
#define UG_ASSERT(expr, msg)
#define UG_THROW(msg)
double number
void UGCheckValues(const dual &number)
Definition van_genuchten.h:41
autodiff::dual dual
Definition van_genuchten.h:37
SmartPtr< T, FreePolicy > make_sp(T *inst)
Definition van_genuchten.h:219
static dual ComputeEffectiveSaturation(dual pc, double lambda, double pb)
Definition van_genuchten.h:220
Definition van_genuchten.h:258
double thetaR
Definition van_genuchten.h:263
double alpha
Definition van_genuchten.h:260
double thetaS
Definition van_genuchten.h:264
double Ksat
Definition van_genuchten.h:266
double beta
Definition van_genuchten.h:261
double pentry
Definition van_genuchten.h:259
Definition van_genuchten.h:447
double Ksat
Definition van_genuchten.h:457
double m
Definition van_genuchten.h:452
double thetaS
Definition van_genuchten.h:455
double thetaR
Definition van_genuchten.h:454
double beta
Definition van_genuchten.h:451
double alpha
Definition van_genuchten.h:448
double n
Definition van_genuchten.h:449
Base class for a parameterized model. Provides serialization.
Definition van_genuchten.h:232
void set_parameters(const TParameter &p)
Definition van_genuchten.h:237
std::string config_string() const
Definition van_genuchten.h:243
IParameterizedModel(const TParameter &p)
Definition van_genuchten.h:235
TParameter m_param
Definition van_genuchten.h:249
const TParameter & get_parameters() const
Definition van_genuchten.h:240
IParameterizedModel()
Definition van_genuchten.h:233
Definition van_genuchten.h:341
static dual ComputeEffectiveSaturation(dual psi_, double alpha, double n, double m)
Effective (reduced) saturation $0 \le \hat S \le 1$.
Definition van_genuchten.h:344
static dual ComputeEffectiveSaturation(dual psi_, double alpha, double n)
Two argument version.
Definition van_genuchten.h:359
Definition van_genuchten.h:62
double n
Definition van_genuchten.h:65
double alpha
Definition van_genuchten.h:63
double thetaR
Definition van_genuchten.h:68
double thetaS
Definition van_genuchten.h:69
double Ksat
Definition van_genuchten.h:71
double m
Definition van_genuchten.h:66