https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PorousFlowAquiferBC.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 "PorousFlowAquiferBC.h"
11
13
16{
19 "Applies a Robin (aquifer) boundary condition: flux = conductance * (P_model - "
20 "P_aquifer(z)), where P_aquifer is the far-field aquifer pressure. Using aquifer_head "
21 "automatically yields zero flux on any hydrostatic boundary whose model "
22 "head equals the aquifer head, even when the boundary has vertical extent.");
23 params.addRequiredParam<RealVectorValue>(
24 "gravity",
25 "Gravitational acceleration vector (m/s^2), e.g. '0 0 -9.81'. "
26 "The elevation at each quadrature point is computed as the component of the "
27 "position vector in the direction opposite to gravity.");
28 params.addParam<Real>("aquifer_head",
29 "Far-field hydraulic head of the aquifer (m above model datum). "
30 "P_aq(z) = rho_nodal * |g| * (aquifer_head - z), where rho_nodal is "
31 "the PorousFlow nodal fluid density at the boundary node. "
32 "Mutually exclusive with aquifer_pressure_at_datum.");
33 params.addParam<Real>("aquifer_pressure_at_datum",
34 "Far-field aquifer pressure at datum_elevation (Pa). "
35 "P_aq(z) = aquifer_pressure_at_datum "
36 " + rho_nodal * |g| * (datum_elevation - z), where rho_nodal is "
37 "the PorousFlow nodal fluid density at the boundary node. "
38 "Mutually exclusive with aquifer_head.");
39 params.addParam<Real>("datum_elevation",
40 0.0,
41 "Elevation of the reference point for aquifer_pressure_at_datum (m).");
42 params.addParam<Real>(
43 "aquifer_conductance",
44 "Conductance per unit boundary area (kg/(m^2*Pa*s)). "
45 "The mass flux leaving the domain is conductance * (P_model - P_aquifer). "
46 "Required when using the aquifer_head formulation. "
47 "Can be estimated as rho * k / (mu * L) where k is aquifer permeability (m^2), "
48 "mu is fluid viscosity (Pa.s), and L is the distance to the far-field (m).");
49 params.addRangeCheckedParam<Real>(
50 "aquifer_distance",
51 "aquifer_distance > 0",
52 "Distance from the boundary to the far-field aquifer (m). "
53 "Required when using the aquifer_pressure_at_datum formulation. "
54 "The conductance is computed internally as rho * k_nn / (mu * aquifer_distance), "
55 "where k_nn is the permeability projected onto the boundary normal, "
56 "rho is the nodal fluid density, and mu is the nodal fluid viscosity.");
57 params.addRangeCheckedParam<Real>(
58 "aquifer_permeability",
59 "aquifer_permeability > 0",
60 "Permeability of the material between the boundary and the far-field aquifer (m^2), "
61 "used as k_nn in the conductance formula of the aquifer_pressure_at_datum formulation. "
62 "If not supplied, the boundary permeability projected onto the boundary normal is used, "
63 "which is appropriate when the aquifer is a continuation of the boundary material.");
64 return params;
65}
66
68 : PorousFlowSink(parameters),
69 _gravity(getParam<RealVectorValue>("gravity")),
70 _g(_gravity.norm()),
71 _use_head_form(isParamValid("aquifer_head")),
72 _aquifer_head(_use_head_form ? getParam<Real>("aquifer_head") : 0.0),
73 _p_datum(!_use_head_form && isParamValid("aquifer_pressure_at_datum")
74 ? getParam<Real>("aquifer_pressure_at_datum")
75 : 0.0),
76 _datum_elevation(getParam<Real>("datum_elevation")),
77 _conductance(_use_head_form && isParamValid("aquifer_conductance")
78 ? getParam<Real>("aquifer_conductance")
79 : 0.0),
80 _aquifer_distance(!_use_head_form && isParamValid("aquifer_distance")
81 ? getParam<Real>("aquifer_distance")
82 : 0.0),
83 _use_aquifer_perm(isParamValid("aquifer_permeability")),
84 _aquifer_permeability(_use_aquifer_perm ? getParam<Real>("aquifer_permeability") : 0.0),
85 _pp(getMaterialProperty<std::vector<Real>>("PorousFlow_porepressure_nodal")),
86 _dpp_dvar(
87 getMaterialProperty<std::vector<std::vector<Real>>>("dPorousFlow_porepressure_nodal_dvar")),
88 _fluid_density_nodal(
89 getMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_nodal")),
90 _dfluid_density_nodal_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
91 "dPorousFlow_fluid_phase_density_nodal_dvar")),
92 _permeability_qp(!_use_head_form && !_use_aquifer_perm
93 ? &getMaterialProperty<RealTensorValue>("PorousFlow_permeability_qp")
94 : nullptr),
95 _fluid_viscosity_nodal(
96 !_use_head_form ? &getMaterialProperty<std::vector<Real>>("PorousFlow_viscosity_nodal")
97 : nullptr),
98 _dfluid_viscosity_nodal_dvar(!_use_head_form
99 ? &getMaterialProperty<std::vector<std::vector<Real>>>(
100 "dPorousFlow_viscosity_nodal_dvar")
101 : nullptr)
102{
103 if (!_involves_fluid)
104 paramError("fluid_phase", "This parameter must be specified.");
105
106 const bool has_head = isParamValid("aquifer_head");
107 const bool has_pdat = isParamValid("aquifer_pressure_at_datum");
108
109 if (has_head && has_pdat)
110 paramError("aquifer_pressure_at_datum",
111 "Specify either aquifer_head or aquifer_pressure_at_datum, not both.");
112
113 if (!has_head && !has_pdat)
114 paramError("aquifer_head",
115 "Either aquifer_head or aquifer_pressure_at_datum must be specified.");
116
117 if (has_head && !isParamValid("aquifer_conductance"))
118 paramError("aquifer_conductance",
119 "This parameter must be specified when using the aquifer_head formulation.");
120
121 if (!has_head && !isParamValid("aquifer_distance"))
122 paramError("aquifer_distance",
123 "This parameter must be specified when using the aquifer_pressure_at_datum "
124 "formulation.");
125
126 if (has_head && _use_aquifer_perm)
127 paramError("aquifer_permeability",
128 "aquifer_permeability is only used with the aquifer_pressure_at_datum "
129 "formulation; with aquifer_head the conductance is supplied directly via "
130 "aquifer_conductance.");
131}
132
133Real
135{
136 // Elevation at the current quadrature point: component in the direction opposite to gravity.
137 // This correctly handles 2D (gravity in y) and 3D (gravity in z) models.
138 const Real z = (_g > 0.0) ? -_q_point[_qp] * (_gravity / _g) : 0.0;
139
140 // Hydrostatic height factor using the nodal fluid density from PorousFlow's EOS.
141 // Using the same density as the rest of PorousFlow makes the correction self-consistent.
142 const Real rho = _fluid_density_nodal[_i][_ph];
143
144 // Far-field aquifer pressure at this elevation
145 Real p_ref;
146 if (_use_head_form)
147 {
148 p_ref = rho * _g * (_aquifer_head - z);
149 return _conductance * (_pp[_i][_ph] - p_ref);
150 }
151 else
152 {
153 p_ref = _p_datum + rho * _g * (_datum_elevation - z);
154 // Conductance computed from permeability and viscosity: C = rho * k_nn / (mu * L).
155 // k_nn is the user-supplied aquifer permeability if given, otherwise the boundary
156 // permeability projected onto the boundary normal.
157 const Real k_nn = _use_aquifer_perm
159 : ((*_permeability_qp)[_qp] * _normals[_qp]) * _normals[_qp];
160 const Real mu = (*_fluid_viscosity_nodal)[_i][_ph];
161 const Real C = rho * k_nn / (mu * _aquifer_distance);
162 return C * (_pp[_i][_ph] - p_ref);
163 }
164}
165
166Real
168{
169 const Real z = (_g > 0.0) ? -_q_point[_qp] * (_gravity / _g) : 0.0;
170 const Real drho_dvar = _dfluid_density_nodal_dvar[_i][_ph][pvar];
171
172 if (_use_head_form)
173 {
174 // Height factor for the density derivative term (zero on purely horizontal boundaries).
175 const Real dz = _aquifer_head - z;
176 // Chain rule: d(p_ref)/d(pvar) = d(rho)/d(pvar) * g * dz
177 return _conductance * (_dpp_dvar[_i][_ph][pvar] - drho_dvar * _g * dz);
178 }
179 else
180 {
181 const Real rho = _fluid_density_nodal[_i][_ph];
182 const Real k_nn = _use_aquifer_perm
184 : ((*_permeability_qp)[_qp] * _normals[_qp]) * _normals[_qp];
185 const Real mu = (*_fluid_viscosity_nodal)[_i][_ph];
186 const Real dmu_dvar = (*_dfluid_viscosity_nodal_dvar)[_i][_ph][pvar];
187
188 // P_aq = p_datum + rho * g * (datum - z)
189 const Real p_aq = _p_datum + rho * _g * (_datum_elevation - z);
190 const Real delta_p = _pp[_i][_ph] - p_aq;
191 const Real C = rho * k_nn / (mu * _aquifer_distance);
192
193 // d(C)/d(pvar): chain rule through rho and mu (perm derivs excluded: constant permeability)
194 const Real dC_dvar = drho_dvar * k_nn / (mu * _aquifer_distance) -
195 rho * k_nn * dmu_dvar / (mu * mu * _aquifer_distance);
196
197 // d(delta_p)/d(pvar): chain rule through P_model and P_aq
198 const Real d_deltap_dvar = _dpp_dvar[_i][_ph][pvar] - drho_dvar * _g * (_datum_elevation - z);
199
200 return dC_dvar * delta_p + C * d_deltap_dvar;
201 }
202}
const double mu
const double rho
registerMooseObject("PorousFlowApp", PorousFlowAquiferBC)
void addRequiredParam(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 addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
unsigned int _qp
unsigned int _i
const MooseArray< Point > & _q_point
const MooseArray< Point > & _normals
void paramError(const std::string &param, Args... args) const
bool isParamValid(const std::string &name) const
Robin (aquifer) boundary condition for PorousFlow.
const MaterialProperty< std::vector< Real > > & _fluid_density_nodal
Nodal fluid density for each phase [kg/m^3] – used in the hydrostatic correction.
static InputParameters validParams()
virtual Real dmultiplier_dvar(unsigned int pvar) const override
d(multiplier)/d(Porous flow variable pvar)
PorousFlowAquiferBC(const InputParameters &parameters)
const MaterialProperty< std::vector< std::vector< Real > > > & _dfluid_density_nodal_dvar
d(nodal fluid density)/d(PorousFlow variable) – needed for the Jacobian
const Real _aquifer_permeability
User-supplied permeability of the material between boundary and aquifer [m^2].
const RealVectorValue _gravity
Gravitational acceleration vector [m/s^2].
const Real _conductance
Conductance per unit boundary area [kg/(m^2 Pa s)] (head formulation only)
virtual Real multiplier() const override
The flux gets multiplied by this quantity.
const Real _datum_elevation
Reference elevation for pressure-at-datum formulation [m].
const Real _aquifer_distance
Distance from boundary to far-field aquifer [m] (pressure formulation only)
const bool _use_aquifer_perm
True when the user supplied aquifer_permeability; false means the boundary k_nn is used.
const Real _g
Magnitude of gravity.
const MaterialProperty< std::vector< std::vector< Real > > > & _dpp_dvar
d(nodal pore pressure)/d(PorousFlow variable)
const Real _aquifer_head
Far-field hydraulic head [m] (head formulation only)
const Real _p_datum
Far-field pressure at datum_elevation [Pa] (pressure formulation only)
const bool _use_head_form
True when aquifer_head formulation is used; false for pressure-at-datum formulation.
const MaterialProperty< std::vector< Real > > & _pp
Nodal pore pressure in each phase [Pa].
Applies a flux sink to a boundary.
const bool _involves_fluid
Whether this BC involves fluid (whether the user has supplied a fluid phase number)
const unsigned int _ph
The phase number.
static InputParameters validParams()