https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PorousFlowPorosity.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
10#include "PorousFlowPorosity.h"
11
14
15template <bool is_ad>
18{
20 params.addParam<bool>(
21 "mechanical", false, "If true, porosity will be a function of total volumetric strain");
22 params.addParam<bool>(
23 "fluid", false, "If true, porosity will be a function of effective porepressure");
24 params.addParam<bool>("thermal", false, "If true, porosity will be a function of temperature");
25 params.addParam<bool>("chemical", false, "If true, porosity will be a function of precipitate");
26 params.addRequiredCoupledVar("porosity_zero",
27 "The porosity at zero volumetric strain and "
28 "reference temperature and reference effective "
29 "porepressure and reference chemistry. This must be a real number "
30 "or a constant monomial variable (not a linear lagrange or other "
31 "type of variable)");
32 params.addParam<Real>("thermal_expansion_coeff",
33 "Volumetric thermal expansion coefficient of the drained porous solid "
34 "skeleton (only used if thermal=true)");
35 params.addRangeCheckedParam<Real>(
36 "biot_coefficient", 1, "biot_coefficient>=0 & biot_coefficient<=1", "Biot coefficient");
37 params.addParam<Real>("biot_coefficient_prime",
38 "Biot coefficient that appears in the term (biot_coefficient_prime - 1) * "
39 "(P - reference_porepressure) / solid_bulk. If not provided, this "
40 "defaults to the standard biot_coefficient");
41 params.addParam<MooseFunctorName>(
42 "solid_bulk", "Bulk modulus of the drained porous solid skeleton (only used if fluid=true)");
43 params.addCoupledVar(
44 "reference_temperature", 0.0, "Reference temperature (only used if thermal=true)");
45 params.addCoupledVar(
46 "reference_porepressure", 0.0, "Reference porepressure (only used if fluid=true)");
47 params.addCoupledVar("reference_chemistry",
48 "Reference values of the solid mineral concentrations "
49 "(m^3(precipitate)/m^3(porous material)), entered as "
50 "a vector (one value per mineral). (Only used if chemical=true)");
51 params.addCoupledVar(
52 "initial_mineral_concentrations",
53 "Initial mineral concentrations (m^3(precipitate)/m^3(porous material)), entered as "
54 "a vector (one value per mineral). (Only used if chemical=true)");
55 params.addParam<std::vector<Real>>("chemical_weights",
56 "When chemical=true, porosity is a linear combination of the "
57 "solid mineral concentrations multiplied by these weights. "
58 "Default=1 for all minerals.");
59 params.addClassDescription("This Material calculates the porosity PorousFlow simulations");
60 return params;
61}
62
63template <bool is_ad>
65 : PorousFlowPorosityExponentialBaseTempl<is_ad>(parameters),
66
67 _mechanical(this->template getParam<bool>("mechanical")),
68 _fluid(this->template getParam<bool>("fluid")),
69 _thermal(this->template getParam<bool>("thermal")),
70 _chemical(this->template getParam<bool>("chemical")),
71 _phi0(coupledValue("porosity_zero")),
72 _biot(this->template getParam<Real>("biot_coefficient")),
73 _exp_coeff(this->isParamValid("thermal_expansion_coeff")
74 ? this->template getParam<Real>("thermal_expansion_coeff")
75 : 0.0),
76 _solid_bulk(this->isParamValid("solid_bulk") ? &(this->template getFunctor<Real>("solid_bulk"))
77 : nullptr),
78 _coeff(this->isParamValid("biot_coefficient_prime")
79 ? (this->template getParam<Real>("biot_coefficient_prime") - 1.0)
80 : (_biot - 1.0)),
81
82 _t_reference(nodalOrQpValue("reference_temperature")),
83 _p_reference(nodalOrQpValue("reference_porepressure")),
84 _num_c_ref(coupledComponents("reference_chemistry")),
85 _c_reference(_num_c_ref),
86 _num_initial_c(coupledComponents("initial_mineral_concentrations")),
87 _initial_c(_num_initial_c),
88 _c_weights(this->isParamValid("chemical_weights")
89 ? this->template getParam<std::vector<Real>>("chemical_weights")
90 : std::vector<Real>(_num_c_ref, 1.0)),
91
92 _porosity_old(
93 _chemical ? (_nodal_material
94 ? &this->template getMaterialPropertyOld<Real>("PorousFlow_porosity_nodal")
95 : &this->template getMaterialPropertyOld<Real>("PorousFlow_porosity_qp"))
96 : nullptr),
97 _vol_strain_qp(_mechanical ? &this->template getGenericMaterialProperty<Real, is_ad>(
98 "PorousFlow_total_volumetric_strain_qp")
99 : nullptr),
100 _dvol_strain_qp_dvar((_mechanical && !is_ad)
101 ? &this->template getMaterialProperty<std::vector<RealGradient>>(
102 "dPorousFlow_total_volumetric_strain_qp_dvar")
103 : nullptr),
104
105 _pf(_fluid ? (_nodal_material ? &this->template getGenericMaterialProperty<Real, is_ad>(
106 "PorousFlow_effective_fluid_pressure_nodal")
107 : &this->template getGenericMaterialProperty<Real, is_ad>(
108 "PorousFlow_effective_fluid_pressure_qp"))
109 : nullptr),
110 _dpf_dvar((_fluid && !is_ad)
111 ? (_nodal_material ? &this->template getMaterialProperty<std::vector<Real>>(
112 "dPorousFlow_effective_fluid_pressure_nodal_dvar")
113 : &this->template getMaterialProperty<std::vector<Real>>(
114 "dPorousFlow_effective_fluid_pressure_qp_dvar"))
115 : nullptr),
116
117 _temperature(_thermal
118 ? (_nodal_material ? &this->template getGenericMaterialProperty<Real, is_ad>(
119 "PorousFlow_temperature_nodal")
120 : &this->template getGenericMaterialProperty<Real, is_ad>(
121 "PorousFlow_temperature_qp"))
122 : nullptr),
123 _dtemperature_dvar((_thermal && !is_ad)
124 ? (_nodal_material
125 ? &this->template getMaterialProperty<std::vector<Real>>(
126 "dPorousFlow_temperature_nodal_dvar")
127 : &this->template getMaterialProperty<std::vector<Real>>(
128 "dPorousFlow_temperature_qp_dvar"))
129 : nullptr),
130
131 _mineral_conc_old(_chemical ? (_nodal_material
132 ? &this->template getMaterialPropertyOld<std::vector<Real>>(
133 "PorousFlow_mineral_concentration_nodal")
134 : &this->template getMaterialPropertyOld<std::vector<Real>>(
135 "PorousFlow_mineral_concentration_qp"))
136 : nullptr),
137 _reaction_rate(_chemical
138 ? (_nodal_material ? &this->template getMaterialProperty<std::vector<Real>>(
139 "PorousFlow_mineral_reaction_rate_nodal")
140 : &this->template getMaterialProperty<std::vector<Real>>(
141 "PorousFlow_mineral_reaction_rate_qp"))
142 : nullptr),
143 _dreaction_rate_dvar(
144 _chemical ? (_nodal_material
145 ? &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
146 "dPorousFlow_mineral_reaction_rate_nodal_dvar")
147 : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
148 "dPorousFlow_mineral_reaction_rate_qp_dvar"))
149 : nullptr),
150 _aq_ph(_dictator.aqueousPhaseNumber()),
151 _saturation(_chemical
152 ? (_nodal_material ? &this->template getMaterialProperty<std::vector<Real>>(
153 "PorousFlow_saturation_nodal")
154 : &this->template getMaterialProperty<std::vector<Real>>(
155 "PorousFlow_saturation_qp"))
156 : nullptr),
157 _dsaturation_dvar(
158 _chemical ? (_nodal_material
159 ? &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
160 "dPorousFlow_saturation_nodal_dvar")
161 : &this->template getMaterialProperty<std::vector<std::vector<Real>>>(
162 "dPorousFlow_saturation_qp_dvar"))
163 : nullptr)
164{
165 // PorousFlowAqueousPreDisChemistry and PorousFlowAqueousPreDisMineral are not templated on is_ad,
166 // so the mineral concentration and reaction rate consumed below exist only as non-AD properties
167 if constexpr (is_ad)
168 if (_chemical)
169 this->mooseError(
170 "ADPorousFlowPorosity does not support chemical=true: the aqueous "
171 "precipitation/dissolution materials are not AD. Use the non-AD PorousFlowPorosity for "
172 "chemistry-coupled porosity");
173
174 if (_thermal && !this->isParamValid("thermal_expansion_coeff"))
175 this->mooseError(
176 "PorousFlowPorosity: When thermal=true you must provide a thermal_expansion_coeff");
177 if (_fluid && !_solid_bulk)
178 this->mooseError("PorousFlowPorosity: When fluid=true you must provide a solid_bulk");
179 if (_chemical && _num_c_ref != _dictator.numAqueousKinetic())
180 this->mooseError(
181 "PorousFlowPorosity: When chemical=true you must provide the reference_chemistry "
182 "values. The Dictator proclaims there should be ",
183 _dictator.numAqueousKinetic(),
184 " of these");
185 if (_chemical && _num_initial_c != _dictator.numAqueousKinetic())
186 this->mooseError("PorousFlowPorosity: When chemical=true you must provide the "
187 "initial_mineral_concentrations. "
188 "The Dictator proclaims there should be ",
189 _dictator.numAqueousKinetic(),
190 " of these");
191 if (_chemical && _c_weights.size() != _dictator.numAqueousKinetic())
192 this->mooseError(
193 "PorousFlowPorosity: When chemical=true you must provde the correct number of "
194 "chemical_weights (which the Dictator knows is ",
195 _dictator.numAqueousKinetic(),
196 ") or do not provide any chemical_weights and use the default value of 1 for each mineral");
197
198 for (unsigned i = 0; i < _num_c_ref; ++i)
199 {
200 _c_reference[i] = &nodalOrQpValue("reference_chemistry", i);
201 _initial_c[i] = &nodalOrQpValue("initial_mineral_concentrations", i);
202 }
203}
204
205template <bool is_ad>
208{
209 /*
210 *
211 * Note the use of the OLD value of porosity here.
212 * This strategy, which breaks the cyclic dependency between porosity
213 * and mineral concentration, is used in
214 * Kernel: PorousFlowPreDis
215 * Material: PorousFlowPorosity
216 * Material: PorousFlowAqueousPreDisChemistry
217 * Material: PorousFlowAqueousPreDisMineral
218 *
219 */
220 GenericReal<is_ad> result = _biot;
221 if (_chemical)
222 {
223 if (_t_step == 0 && !_app.isRestarting())
224 for (unsigned i = 0; i < _num_c_ref; ++i)
225 result -= _c_weights[i] * (*_initial_c[i])[_qp];
226 else
227 for (unsigned i = 0; i < _num_c_ref; ++i)
228 result -= _c_weights[i] * ((*_mineral_conc_old)[_qp][i] + _dt * (*_porosity_old)[_qp] *
229 (*_saturation)[_qp][_aq_ph] *
230 (*_reaction_rate)[_qp][i]);
231 }
232 return result;
233}
234
235template <bool is_ad>
236Real
238{
239 Real result = 0.0;
240 if (_chemical && (_t_step >= 1 || _app.isRestarting()))
241 for (unsigned i = 0; i < _num_c_ref; ++i)
242 result -= _c_weights[i] * _dt * (*_porosity_old)[_qp] *
243 ((*_saturation)[_qp][_aq_ph] * (*_dreaction_rate_dvar)[_qp][i][pvar] +
244 (*_dsaturation_dvar)[_qp][_aq_ph][pvar] * (*_reaction_rate)[_qp][i]);
245 return result;
246}
247
248template <bool is_ad>
251{
252 // note the [0] below: _phi0 is a constant monomial and we use [0] regardless of _nodal_material
253 GenericReal<is_ad> result = _phi0[0];
254 if (_chemical)
255 {
256 if (_t_step == 0 && !_app.isRestarting())
257 for (unsigned i = 0; i < _num_c_ref; ++i)
258 result -= _c_weights[i] * ((*_initial_c[i])[_qp] - (*_c_reference[i])[_qp]);
259 else
260 for (unsigned i = 0; i < _num_c_ref; ++i)
261 result -= _c_weights[i] * ((*_mineral_conc_old)[_qp][i] +
262 _dt * (*_porosity_old)[_qp] * (*_saturation)[_qp][_aq_ph] *
263 (*_reaction_rate)[_qp][i] -
264 (*_c_reference[i])[_qp]);
265 }
266 return result;
267}
268
269template <bool is_ad>
270Real
272{
273 Real result = 0.0;
274 if (_chemical && (_t_step >= 1 || _app.isRestarting()))
275 for (unsigned i = 0; i < _num_c_ref; ++i)
276 result -= _c_weights[i] * _dt * (*_porosity_old)[_qp] *
277 ((*_saturation)[_qp][_aq_ph] * (*_dreaction_rate_dvar)[_qp][i][pvar] +
278 (*_dsaturation_dvar)[_qp][_aq_ph][pvar] * (*_reaction_rate)[_qp][i]);
279 return result;
280}
281
282template <bool is_ad>
285{
286 GenericReal<is_ad> result = 0.0;
287
288 if (_thermal)
289 result += _exp_coeff * ((*_temperature)[_qp] - _t_reference[_qp]);
290
291 if (_fluid)
292 {
293 Real solid_bulk;
294 // Using Qp 0 can leverage the functor caching
295 // TODO: Find a way to effectively use subdomain-constant-ness
296 unsigned int qp_used = (_constant_option == Material::ConstantTypeEnum::NONE) ? _qp : 0;
297 if (_nodal_material)
298 {
299 const std::set<SubdomainID> subdomain_set = {_current_elem->subdomain_id()};
300 const Moose::NodeArg space_arg = {_current_elem->node_ptr(qp_used), &subdomain_set};
301 solid_bulk = (*_solid_bulk)(space_arg, Moose::currentState());
302 }
303 else if (_bnd)
304 {
305 const Moose::ElemSideQpArg space_arg = {
306 _current_elem, _current_side, qp_used, _qrule, _q_point[qp_used]};
307 solid_bulk = (*_solid_bulk)(space_arg, Moose::currentState());
308 }
309 else
310 {
311 const Moose::ElemQpArg space_arg = {_current_elem, qp_used, _qrule, _q_point[qp_used]};
312 solid_bulk = (*_solid_bulk)(space_arg, Moose::currentState());
313 }
314 if (solid_bulk <= 0)
315 this->mooseError("PorousFlowPorosity: solid_bulk must be larger than Zero");
316 result += _coeff / solid_bulk * ((*_pf)[_qp] - _p_reference[_qp]);
317 }
318
319 if (_mechanical)
320 {
321 // Note that in the following _strain[_qp] is evaluated at q quadpoint
322 // So _porosity_nodal[_qp], which should be the nodal value of porosity
323 // actually uses the strain at a quadpoint. This
324 // is OK for LINEAR elements, as strain is constant over the element anyway.
325 const unsigned qp_to_use =
326 (_nodal_material && (_bnd || _strain_at_nearest_qp) ? nearestQP(_qp) : _qp);
327 result += -(*_vol_strain_qp)[qp_to_use];
328 }
329
330 return result;
331}
332
333template <bool is_ad>
334Real
336{
337 Real result = 0.0;
338
339 if (_thermal)
340 result += _exp_coeff * (*_dtemperature_dvar)[_qp][pvar];
341
342 if (_fluid)
343 {
344 Real solid_bulk;
345 // Using Qp 0 can leverage the functor caching
346 // TODO: Find a way to effectively use subdomain-constant-ness
347 unsigned int qp_used = (_constant_option == Material::ConstantTypeEnum::NONE) ? _qp : 0;
348 if (_nodal_material)
349 {
350 const std::set<SubdomainID> subdomain_set = {_current_elem->subdomain_id()};
351 const Moose::NodeArg space_arg = {_current_elem->node_ptr(qp_used), &subdomain_set};
352 solid_bulk = (*_solid_bulk)(space_arg, Moose::currentState());
353 }
354 else if (_bnd)
355 {
356 const Moose::ElemSideQpArg space_arg = {
357 _current_elem, _current_side, qp_used, _qrule, _q_point[qp_used]};
358 solid_bulk = (*_solid_bulk)(space_arg, Moose::currentState());
359 }
360 else
361 {
362 const Moose::ElemQpArg space_arg = {_current_elem, qp_used, _qrule, _q_point[qp_used]};
363 solid_bulk = (*_solid_bulk)(space_arg, Moose::currentState());
364 }
365 if (solid_bulk <= 0)
366 this->mooseError("PorousFlowPorosity: solid_bulk must be larger than Zero.");
367 result += _coeff / solid_bulk * (*_dpf_dvar)[_qp][pvar];
368 }
369
370 return result;
371}
372
373template <bool is_ad>
374RealGradient
376{
377 RealGradient result(0.0, 0.0, 0.0);
378 if (_mechanical)
379 {
380 const unsigned qp_to_use =
381 (_nodal_material && (_bnd || _strain_at_nearest_qp) ? nearestQP(_qp) : _qp);
382 result += -(*_dvol_strain_qp_dvar)[qp_to_use][pvar];
383 }
384 return result;
385}
386
387template class PorousFlowPorosityTempl<false>;
388template class PorousFlowPorosityTempl<true>;
void mooseError(Args &&... args)
Moose::GenericType< Real, is_ad > GenericReal
registerMooseObject("PorousFlowApp", PorousFlowPorosity)
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
void addCoupledVar(const std::string &name, const std::string &doc_string)
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
Base class Material designed to provide the porosity.
Material designed to provide the porosity in PorousFlow simulations chemistry + biot + (phi0 - refere...
const bool _chemical
Porosity is a function of chemistry.
virtual GenericReal< is_ad > atZeroQp() const override
Returns "b" at the quadpoint (porosity = a + (b - a) * exp(decay))
virtual GenericReal< is_ad > decayQp() const override
Returns "decay" at the quadpoint (porosity = a + (b - a) * exp(decay))
const unsigned _num_c_ref
Number of reference mineral concentrations provided by user.
const bool _fluid
Porosity is a function of effective porepressure.
const bool _thermal
Porosity is a function of temperature.
std::vector< Real > _c_weights
Weights for the mineral concentrations.
const unsigned _num_initial_c
Number of reference mineral concentrations provided by user.
static InputParameters validParams()
virtual GenericReal< is_ad > atNegInfinityQp() const override
Returns "a" at the quadpoint (porosity = a + (b - a) * exp(decay))
PorousFlowPorosityTempl(const InputParameters &parameters)
virtual Real datZeroQp(unsigned pvar) const override
d(b)/d(PorousFlow variable pvar)
std::vector< const VariableValue * > _c_reference
Reference mineral concentrations.
const Moose::Functor< Real > * _solid_bulk
Drained bulk modulus of the porous skeleton (as a functor; can be variable, function,...
virtual RealGradient ddecayQp_dgradvar(unsigned pvar) const override
d(decay)/d(grad(PorousFlow variable pvar))
virtual Real ddecayQp_dvar(unsigned pvar) const override
d(decay)/d(PorousFlow variable pvar)
virtual Real datNegInfinityQp(unsigned pvar) const override
d(a)/d(PorousFlow variable pvar)
std::vector< const VariableValue * > _initial_c
Reference mineral concentrations.
StateArg currentState()