https://mooseframework.inl.gov
Loading...
Searching...
No Matches
FVPorousFlowAquiferBC.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#include "PorousFlowDictator.h"
12
14
17{
20 "Applies a Robin (aquifer) boundary condition: flux = conductance * (P_model - "
21 "P_aquifer(z)), where P_aquifer is the far-field aquifer pressure. Using aquifer_head "
22 "automatically yields zero flux on any hydrostatic boundary whose model "
23 "head equals the aquifer head, even when the boundary has vertical extent. "
24 "FV analogue of PorousFlowAquiferBC.");
25 params.addRequiredParam<UserObjectName>("PorousFlowDictator",
26 "The PorousFlowDictator UserObject");
27 params.addParam<unsigned int>("phase", 0, "The fluid phase for this BC");
28 params.addParam<unsigned int>("fluid_component", 0, "The fluid component for this BC");
29 params.addRequiredParam<RealVectorValue>(
30 "gravity",
31 "Gravitational acceleration vector (m/s^2), e.g. '0 0 -9.81'. "
32 "The elevation of the boundary cell is computed as the component of the "
33 "cell-centroid position vector in the direction opposite to gravity.");
34 params.addParam<Real>("aquifer_head",
35 "Far-field hydraulic head of the aquifer (m above model datum). "
36 "P_aq(z) = rho * |g| * (aquifer_head - z), where rho is "
37 "the fluid density in the boundary cell. "
38 "Mutually exclusive with aquifer_pressure_at_datum.");
39 params.addParam<Real>("aquifer_pressure_at_datum",
40 "Far-field aquifer pressure at datum_elevation (Pa). "
41 "P_aq(z) = aquifer_pressure_at_datum "
42 " + rho * |g| * (datum_elevation - z), where rho is "
43 "the fluid density in the boundary cell. "
44 "Mutually exclusive with aquifer_head.");
45 params.addParam<Real>("datum_elevation",
46 0.0,
47 "Elevation of the reference point for aquifer_pressure_at_datum (m).");
48 params.addParam<Real>(
49 "aquifer_conductance",
50 "Conductance per unit boundary area (kg/(m^2*Pa*s)). "
51 "The mass flux leaving the domain is conductance * (P_model - P_aquifer). "
52 "Required when using the aquifer_head formulation. "
53 "Can be estimated as rho * k / (mu * L) where k is aquifer permeability (m^2), "
54 "mu is fluid viscosity (Pa.s), and L is the distance to the far-field (m).");
55 params.addRangeCheckedParam<Real>(
56 "aquifer_distance",
57 "aquifer_distance > 0",
58 "Distance from the boundary to the far-field aquifer (m). "
59 "Required when using the aquifer_pressure_at_datum formulation. "
60 "The conductance is computed internally as rho * k_nn / (mu * aquifer_distance), "
61 "where k_nn is the permeability projected onto the boundary normal, "
62 "rho is the fluid density, and mu is the fluid viscosity in the boundary cell.");
63 params.addRangeCheckedParam<Real>(
64 "aquifer_permeability",
65 "aquifer_permeability > 0",
66 "Permeability of the material between the boundary and the far-field aquifer (m^2), "
67 "used as k_nn in the conductance formula of the aquifer_pressure_at_datum formulation. "
68 "If not supplied, the boundary permeability projected onto the boundary normal is used, "
69 "which is appropriate when the aquifer is a continuation of the boundary material.");
70 return params;
71}
72
74 : FVFluxBC(params),
75 _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
76 _num_phases(_dictator.numPhases()),
77 _phase(getParam<unsigned int>("phase")),
78 _fluid_component(getParam<unsigned int>("fluid_component")),
79 _gravity(getParam<RealVectorValue>("gravity")),
80 _g(_gravity.norm()),
81 _use_head_form(isParamValid("aquifer_head")),
82 _aquifer_head(_use_head_form ? getParam<Real>("aquifer_head") : 0.0),
83 _p_datum(!_use_head_form && isParamValid("aquifer_pressure_at_datum")
84 ? getParam<Real>("aquifer_pressure_at_datum")
85 : 0.0),
86 _datum_elevation(getParam<Real>("datum_elevation")),
87 _conductance(_use_head_form && isParamValid("aquifer_conductance")
88 ? getParam<Real>("aquifer_conductance")
89 : 0.0),
90 _aquifer_distance(!_use_head_form && isParamValid("aquifer_distance")
91 ? getParam<Real>("aquifer_distance")
92 : 0.0),
93 _use_aquifer_perm(isParamValid("aquifer_permeability")),
94 _aquifer_permeability(_use_aquifer_perm ? getParam<Real>("aquifer_permeability") : 0.0),
95 _density(getADMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_qp")),
96 _density_neighbor(
97 getNeighborADMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_qp")),
98 _viscosity(getADMaterialProperty<std::vector<Real>>("PorousFlow_viscosity_qp")),
99 _viscosity_neighbor(
100 getNeighborADMaterialProperty<std::vector<Real>>("PorousFlow_viscosity_qp")),
101 _relperm(getADMaterialProperty<std::vector<Real>>("PorousFlow_relative_permeability_qp")),
102 _relperm_neighbor(
103 getNeighborADMaterialProperty<std::vector<Real>>("PorousFlow_relative_permeability_qp")),
104 _mass_fractions(
105 getADMaterialProperty<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_qp")),
106 _mass_fractions_neighbor(
107 getNeighborADMaterialProperty<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_qp")),
108 _permeability(getADMaterialProperty<RealTensorValue>("PorousFlow_permeability_qp")),
109 _permeability_neighbor(
110 getNeighborADMaterialProperty<RealTensorValue>("PorousFlow_permeability_qp")),
111 _pressure(getADMaterialProperty<std::vector<Real>>("PorousFlow_porepressure_qp")),
112 _pressure_neighbor(
113 getNeighborADMaterialProperty<std::vector<Real>>("PorousFlow_porepressure_qp"))
114{
115 if (_phase >= _num_phases)
117 "phase",
118 "The Dictator proclaims that the maximum fluid phase index in this simulation is ",
119 _num_phases - 1,
120 " whereas you have used ",
121 _phase,
122 ". Remember that indexing starts at 0. The Dictator does not take such mistakes lightly.");
123
126 "fluid_component",
127 "The Dictator proclaims that the maximum fluid component index in this simulation is ",
129 " whereas you have used ",
131 ". Remember that indexing starts at 0.");
132
133 const bool has_head = isParamValid("aquifer_head");
134 const bool has_pdat = isParamValid("aquifer_pressure_at_datum");
135
136 if (has_head && has_pdat)
137 paramError("aquifer_pressure_at_datum",
138 "Specify either aquifer_head or aquifer_pressure_at_datum, not both.");
139
140 if (!has_head && !has_pdat)
141 paramError("aquifer_head",
142 "Either aquifer_head or aquifer_pressure_at_datum must be specified.");
143
144 if (has_head && !isParamValid("aquifer_conductance"))
145 paramError("aquifer_conductance",
146 "This parameter must be specified when using the aquifer_head formulation.");
147
148 if (!has_head && !isParamValid("aquifer_distance"))
149 paramError("aquifer_distance",
150 "This parameter must be specified when using the aquifer_pressure_at_datum "
151 "formulation.");
152
153 if (has_head && _use_aquifer_perm)
154 paramError("aquifer_permeability",
155 "aquifer_permeability is only used with the aquifer_pressure_at_datum "
156 "formulation; with aquifer_head the conductance is supplied directly via "
157 "aquifer_conductance.");
158}
159
160ADReal
162{
163 const bool out_of_elem = (_face_type == FaceInfo::VarFaceNeighbors::ELEM);
164
165 // Elevation of the boundary-cell centroid: component in the direction opposite to
166 // gravity. The aquifer pressure is evaluated at the same elevation as the cell
167 // pressure so that hydrostatic equilibrium gives exactly zero flux on boundaries
168 // of any orientation.
169 const Point & centroid =
171 const Real z = (_g > 0.0) ? -centroid * (_gravity / _g) : 0.0;
172
173 const auto & rho = out_of_elem ? _density[_qp][_phase] : _density_neighbor[_qp][_phase];
174 const auto & p = out_of_elem ? _pressure[_qp][_phase] : _pressure_neighbor[_qp][_phase];
175
176 // Far-field aquifer pressure at the cell-centroid elevation, and the conductance
177 ADReal p_aq, conductance;
178 if (_use_head_form)
179 {
180 p_aq = rho * _g * (_aquifer_head - z);
181 conductance = _conductance;
182 }
183 else
184 {
185 p_aq = _p_datum + rho * _g * (_datum_elevation - z);
186 // Conductance computed from permeability and viscosity: C = rho * k_nn / (mu * L).
187 // k_nn is the user-supplied aquifer permeability if given, otherwise the boundary
188 // cell permeability projected onto the boundary normal.
189 const auto & mu = out_of_elem ? _viscosity[_qp][_phase] : _viscosity_neighbor[_qp][_phase];
190 ADReal k_nn;
193 else
194 {
195 const auto & perm = out_of_elem ? _permeability[_qp] : _permeability_neighbor[_qp];
196 k_nn = (perm * _normal) * _normal;
197 }
198 conductance = rho * k_nn / (mu * _aquifer_distance);
199 }
200
201 const auto & massfrac = out_of_elem ? _mass_fractions[_qp][_phase][_fluid_component]
203 const auto & relperm = out_of_elem ? _relperm[_qp][_phase] : _relperm_neighbor[_qp][_phase];
204
205 const auto flux = massfrac * relperm * conductance * (p - p_aq);
206
207 return out_of_elem ? flux : -flux;
208}
DualNumber< Real, DNDerivativeType, true > ADReal
registerADMooseObject("PorousFlowApp", FVPorousFlowAquiferBC)
const double mu
const Real p
const double rho
void ErrorVector unsigned int
const FaceInfo * _face_info
ADRealVectorValue _normal
FaceInfo::VarFaceNeighbors _face_type
const unsigned int _qp
static InputParameters validParams()
Robin (aquifer) boundary condition for finite-volume PorousFlow.
const Real _aquifer_head
Far-field hydraulic head [m] (head formulation only)
const ADMaterialProperty< std::vector< std::vector< Real > > > & _mass_fractions_neighbor
const ADMaterialProperty< RealTensorValue > & _permeability_neighbor
const ADMaterialProperty< std::vector< Real > > & _viscosity
Fluid viscosity.
const ADMaterialProperty< std::vector< Real > > & _relperm_neighbor
const ADMaterialProperty< std::vector< Real > > & _relperm
Relative permeability.
const Real _p_datum
Far-field pressure at datum_elevation [Pa] (pressure formulation only)
const ADMaterialProperty< RealTensorValue > & _permeability
Permeability.
const unsigned int _phase
Index of the fluid phase this BC applies to.
const PorousFlowDictator & _dictator
UserObject that holds information (number of phases, components, etc)
const unsigned int _num_phases
Number of fluid phases present.
const bool _use_aquifer_perm
True when the user supplied aquifer_permeability; false means the boundary k_nn is used.
const RealVectorValue _gravity
Gravitational acceleration vector [m/s^2].
const ADMaterialProperty< std::vector< Real > > & _density
Fluid density.
const ADMaterialProperty< std::vector< Real > > & _pressure
Fluid pressure.
static InputParameters validParams()
const bool _use_head_form
True when aquifer_head formulation is used; false for pressure-at-datum formulation.
const ADMaterialProperty< std::vector< Real > > & _pressure_neighbor
const Real _conductance
Conductance per unit boundary area [kg/(m^2 Pa s)] (head formulation only)
const Real _aquifer_permeability
User-supplied permeability of the material between boundary and aquifer [m^2].
FVPorousFlowAquiferBC(const InputParameters &params)
const Real _datum_elevation
Reference elevation for pressure-at-datum formulation [m].
virtual ADReal computeQpResidual() override
const Real _aquifer_distance
Distance from boundary to far-field aquifer [m] (pressure formulation only)
const Real _g
Magnitude of gravity.
const ADMaterialProperty< std::vector< Real > > & _viscosity_neighbor
const ADMaterialProperty< std::vector< Real > > & _density_neighbor
const unsigned int _fluid_component
Index of the fluid component this BC applies to.
const ADMaterialProperty< std::vector< std::vector< Real > > > & _mass_fractions
Mass fraction of fluid components in fluid phases.
const Point & neighborCentroid() const
const Point & elemCentroid() const
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)
void paramError(const std::string &param, Args... args) const
bool isParamValid(const std::string &name) const
This holds maps between the nonlinear variables used in a PorousFlow simulation and the variable numb...
unsigned int numComponents() const
The number of fluid components.