Plugins
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 
34 namespace ug{
35 namespace Richards{
36 
38 
39 // const double one = 1.0;
40 
41 inline 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 /*
86 class BrooksCorey
87 {
88 public:
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 
100 protected:
101  double m_pd; // entry pressure
102  double m_lambda; // ~pore size distribution
103 
104 
105 };
106 */
107 
108 
109 
110 
111 
113 
120 template <typename TDerived>
122 {
123 
124 protected:
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 
141 public:
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 
183 public: // 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 
230 template <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 {
279 public:
283 
284  friend base_type;
286 
288 
289 protected:
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 
315  inline dual RelativePermeability_(dual pc) const
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 {
369 public:
373 
374  friend base_type;
376 
378 
379 
380 protected:
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 
475 class HaverkampModel : public IRichardsModel<HaverkampModel>, public IParameterizedModel<HaverkampParameters>
476 {
477 public:
481 
482  friend base_type;
484 
486  {}
487 
488 #ifdef UG_JSON
489  // TODO: Move to Factory
490  HaverkampModel(const char* json)
491  {
492  nlohmann::json j = nlohmann::json::parse(json);
493  parameter_type p = j.get<parameter_type>();
494  set_parameters(p);
495  }
496 #endif
497 
498 
499 
500 protected:
501 
502 
503  // p_c = p_a - p_w : Kapillardruck
504  // psi = p_c / (rho_w * g) : Kapillardruckhoehe
505 
506 
508  dual Saturation_(dual psi_) const
509  {
510  const parameter_type &p = get_parameters();
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  {
521  const parameter_type &p = get_parameters();
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
528  dual Conductivity_(dual psi_) const
529  {
530  const parameter_type &p = get_parameters();
531  return p.Ksat*RelativePermeability_(psi_);
532  }
533 
534 };
535 
536 
539  public IParameterizedModel<HaverkampParameters>,
540  public IRichardsModel<GardnerModel>
541 {
542 public:
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 
565 protected:
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 
602 template <typename TModel, typename TParameter = typename TModel::parameter_type>
603 SmartPtr<TModel> CreateModel(const char *jstring) {
604 
605  SmartPtr<TModel> inst = SPNULL;
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 
622 SmartPtr<VanGenuchtenModel> CreateVanGenuchtenModel(const char *json);
623 
624 
626 struct 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.
649 namespace 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
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
double dConductivity_dH(double H)
Definition: van_genuchten.h:207
const TDerived * me() const
Definition: van_genuchten.h:126
void get_conductivity(double H, double &K, double &dKdH) const
Calls Conductivity_.
Definition: van_genuchten.h:169
TDerived * me()
Definition: van_genuchten.h:129
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
const TParameter & get_parameters() const
Definition: van_genuchten.h:240
IParameterizedModel(const TParameter &p)
Definition: van_genuchten.h:235
TParameter m_param
Definition: van_genuchten.h:249
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