https://mooseframework.inl.gov
PorousFlowPorosityExponentialBase.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
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 
11 
12 #include <limits>
13 
16 {
18  params.addParam<bool>("strain_at_nearest_qp",
19  false,
20  "When calculating nodal porosity that depends on strain, use the strain at "
21  "the nearest quadpoint. This adds a small extra computational burden, and "
22  "is not necessary for simulations involving only linear lagrange elements. "
23  " If you set this to true, you will also want to set the same parameter to "
24  "true for related Kernels and Materials");
25  params.addParam<bool>("ensure_positive",
26  true,
27  "Modify the usual exponential relationships that "
28  "governs porosity so that porosity is always "
29  "positive");
30  params.addParam<Real>(
31  "porosity_min",
32  std::numeric_limits<Real>::lowest(),
33  "Minimum allowed value of the porosity: if the computed porosity is less than this value, "
34  "porosity is set to this value instead. By default no floor is imposed. The "
35  "ensure_positive "
36  "transform only acts for decay > 0, so chemistry-driven (precipitation) porosity is "
37  "otherwise "
38  "unbounded below and can become negative once pore space is filled by mineral; set this to a "
39  "small positive value in that case.");
40  params.addParam<Real>("zero_modifier",
41  1E-3,
42  "If the porosity_min floor is active, the porosity derivatives are set to "
43  "zero_modifier times their unfloored values (rather than exactly zero) to "
44  "hint to the Newton-Krylov nonlinear solver that porosity "
45  "is not strictly constant, which aids convergence");
46  params.addParamNamesToGroup("zero_modifier", "Advanced");
47  params.addClassDescription("Base class Material for porosity that is computed via an exponential "
48  "relationship with coupled variables (strain, porepressure, "
49  "temperature, chemistry)");
50  return params;
51 }
52 
54  const InputParameters & parameters)
55  : PorousFlowPorosityBase(parameters),
56  _strain_at_nearest_qp(getParam<bool>("strain_at_nearest_qp")),
57  _ensure_positive(getParam<bool>("ensure_positive")),
58  _porosity_min(getParam<Real>("porosity_min")),
59  _zero_modifier(getParam<Real>("zero_modifier"))
60 {
61 }
62 
63 void
65 {
66  const Real a = atNegInfinityQp();
67  const Real b = atZeroQp();
68  mooseAssert(a > b, "PorousFlowPorosityExponentialBase a must be larger than b");
69  const Real decay = decayQp();
70 
71  if (decay <= 0.0 || !_ensure_positive)
72  _porosity[_qp] = a + (b - a) * std::exp(decay);
73  else
74  {
75  const Real c = std::log(a / (a - b));
76  const Real expx = std::exp(-decay / c);
77  _porosity[_qp] = a + (b - a) * std::exp(c * (1.0 - expx));
78  }
79 
80  if (_porosity[_qp] < _porosity_min)
81  _porosity[_qp] = _porosity_min;
82 }
83 
84 void
86 {
87  const Real a = atNegInfinityQp();
88  const Real b = atZeroQp();
89  const Real decay = decayQp();
90  Real exp_term = 1.0; // set appropriately below
91 
92  Real deriv = 0.0; // = d(porosity)/d(decay)
93  if (decay <= 0.0 || !_ensure_positive)
94  {
95  exp_term = std::exp(decay);
96  _porosity[_qp] = a + (b - a) * exp_term;
97  deriv = _porosity[_qp] - a;
98  }
99  else
100  {
101  const Real c = std::log(a / (a - b));
102  const Real expx = std::exp(-decay / c);
103  // note that at decay = 0, we have expx = 1, so porosity = a + b - a = b
104  // and at decay = infinity, expx = 0, so porosity = a + (b - a) * a / (a - b) = 0
105  exp_term = std::exp(c * (1.0 - expx));
106  _porosity[_qp] = a + (b - a) * exp_term;
107  deriv = (_porosity[_qp] - a) * expx;
108  }
109 
110  (*_dporosity_dvar)[_qp].resize(_num_var);
111  (*_dporosity_dgradvar)[_qp].resize(_num_var);
112  for (unsigned int v = 0; v < _num_var; ++v)
113  {
114  (*_dporosity_dvar)[_qp][v] = ddecayQp_dvar(v) * deriv;
115  (*_dporosity_dgradvar)[_qp][v] = ddecayQp_dgradvar(v) * deriv;
116 
117  const Real da = datNegInfinityQp(v);
118  const Real db = datZeroQp(v);
119  (*_dporosity_dvar)[_qp][v] += da * (1 - exp_term) + db * exp_term;
120 
121  if (!(decay <= 0.0 || !_ensure_positive))
122  {
123  const Real c = std::log(a / (a - b));
124  const Real expx = std::exp(-decay / c);
125  const Real dc = (a - b) * (da * b / a - db) / std::pow(a, 2);
126  (*_dporosity_dvar)[_qp][v] += (b - a) * exp_term * dc * (1 - expx - expx / c);
127  }
128  }
129 
130  // Apply the porosity floor last, after the unfloored derivatives above have been
131  // formed. When floored, soften the derivatives with _zero_modifier so the Newton
132  // process still sees porosity as weakly varying (cf. PorousFlowPorosityLinear).
133  if (_porosity[_qp] < _porosity_min)
134  {
135  _porosity[_qp] = _porosity_min;
136  for (unsigned int v = 0; v < _num_var; ++v)
137  {
138  (*_dporosity_dvar)[_qp][v] *= _zero_modifier;
139  (*_dporosity_dgradvar)[_qp][v] *= _zero_modifier;
140  }
141  }
142 }
const bool _ensure_positive
for decayQp() > 0, porosity can be negative when using porosity = a + (b - a) * exp(decay).
virtual Real atZeroQp() const =0
Returns "b" at the quadpoint (porosity = a + (b - a) * exp(decay))
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const double v
PorousFlowPorosityExponentialBase(const InputParameters &parameters)
const GeochemicalDatabaseReader db("database/moose_testdb.json", true, true, false)
static InputParameters validParams()
Real deriv(unsigned n, unsigned alpha, unsigned beta, Real x)
virtual Real datZeroQp(unsigned pvar) const =0
d(a)/d(PorousFlow variable pvar)
Base class Material designed to provide the porosity.
const Real _porosity_min
Minimum allowed porosity.
virtual Real decayQp() const =0
Returns "decay" at the quadpoint (porosity = a + (b - a) * exp(decay))
const unsigned int _num_var
Number of PorousFlow variables.
virtual Real atNegInfinityQp() const =0
Returns "a" at the quadpoint (porosity = a + (b - a) * exp(decay))
virtual RealGradient ddecayQp_dgradvar(unsigned pvar) const =0
d(decay)/d(grad(PorousFlow variable pvar))
GenericMaterialProperty< Real, is_ad > & _porosity
Computed porosity at the nodes or quadpoints.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual Real datNegInfinityQp(unsigned pvar) const =0
d(a)/d(PorousFlow variable pvar)
virtual Real ddecayQp_dvar(unsigned pvar) const =0
d(decay)/d(PorousFlow variable pvar)
void addClassDescription(const std::string &doc_string)
const Real _zero_modifier
If the porosity_min floor is active the porosity derivatives are set to _zero_modifier times their un...
MooseUnits pow(const MooseUnits &, int)
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)