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