https://mooseframework.inl.gov
PorousFlowOutflowBC.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 "PorousFlowOutflowBC.h"
11 
12 #include "MooseVariable.h"
13 #include "libmesh/string_to_enum.h"
14 #include "libmesh/quadrature.h"
15 
17 
20 {
22  params.addRequiredParam<UserObjectName>(
23  "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names");
24  params.addRequiredParam<RealVectorValue>("gravity",
25  "Gravitational acceleration vector downwards (m/s^2)");
26  MooseEnum flux_type_enum("fluid heat", "fluid");
27  params.addParam<MooseEnum>(
28  "flux_type",
29  flux_type_enum,
30  "The type of boundary condition to apply. 'fluid' means this boundary condition will allow "
31  "a fluid component to flow freely from the boundary. 'heat' means this boundary condition "
32  "will allow heat energy to flow freely from the boundary");
33  params.addParam<unsigned int>(
34  "mass_fraction_component",
35  0,
36  "The index corresponding to a fluid "
37  "component. If supplied, the residual contribution will be "
38  "multiplied by the mass fraction, corresponding to allowing the "
39  "given mass fraction to flow freely from the boundary. This is ignored if flux_type = heat");
40  params.addParam<bool>("multiply_by_density",
41  true,
42  "If true, this BC represents mass flux. If false, it represents volume "
43  "flux. User input of this flag is ignored if flux_type = heat as "
44  "multiply_by_density should always be true in that case");
45  params.addParam<bool>(
46  "include_relperm",
47  true,
48  "If true, the Darcy flux will include the relative permeability. If false, the relative "
49  "permeability will not be used, which must only be used for fully-saturated situations "
50  "where there is no notion of relative permeability");
51  params.addParam<Real>(
52  "multiplier",
53  1.0,
54  "Multiply the flux by this number. This is mainly used for testing purposes");
55  params.addParamNamesToGroup("multiplier", "Advanced");
56  params.addClassDescription(
57  "Applies an 'outflow' boundary condition, which allows fluid components or heat energy to "
58  "flow freely out of the boundary as if it weren't there. This is fully upwinded");
59  return params;
60 }
61 
63  : IntegratedBC(parameters),
64  _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
65  _num_phases(_dictator.numPhases()),
66  _perm_derivs(_dictator.usePermDerivs()),
67  _flux_type(getParam<MooseEnum>("flux_type").getEnum<FluxTypeChoiceEnum>()),
68  _sp(getParam<unsigned>("mass_fraction_component")),
69  _multiply_by_density(
70  _flux_type == FluxTypeChoiceEnum::FLUID ? getParam<bool>("multiply_by_density") : true),
71  _include_relperm(getParam<bool>("include_relperm")),
72  _gravity(getParam<RealVectorValue>("gravity")),
73  _multiplier(getParam<Real>("multiplier")),
74  _grad_p(getMaterialProperty<std::vector<RealGradient>>("PorousFlow_grad_porepressure_qp")),
75  _dgrad_p_dgrad_var(getMaterialProperty<std::vector<std::vector<Real>>>(
76  "dPorousFlow_grad_porepressure_qp_dgradvar")),
77  _dgrad_p_dvar(getMaterialProperty<std::vector<std::vector<RealGradient>>>(
78  "dPorousFlow_grad_porepressure_qp_dvar")),
79  _fluid_density_qp(getMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_qp")),
80  _dfluid_density_qp_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
81  "dPorousFlow_fluid_phase_density_qp_dvar")),
82  _permeability(getMaterialProperty<RealTensorValue>("PorousFlow_permeability_qp")),
83  _dpermeability_dvar(
84  getMaterialProperty<std::vector<RealTensorValue>>("dPorousFlow_permeability_qp_dvar")),
85  _dpermeability_dgradvar(getMaterialProperty<std::vector<std::vector<RealTensorValue>>>(
86  "dPorousFlow_permeability_qp_dgradvar")),
87  _fluid_viscosity(getMaterialProperty<std::vector<Real>>("PorousFlow_viscosity_nodal")),
88  _dfluid_viscosity_dvar(
89  getMaterialProperty<std::vector<std::vector<Real>>>("dPorousFlow_viscosity_nodal_dvar")),
90 
91  _has_density(hasMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_nodal") &&
92  hasMaterialProperty<std::vector<std::vector<Real>>>(
93  "dPorousFlow_fluid_phase_density_nodal_dvar")),
94  _has_mass_fraction(
95  hasMaterialProperty<std::vector<std::vector<Real>>>("PorousFlow_mass_frac_nodal") &&
96  hasMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
97  "dPorousFlow_mass_frac_nodal_dvar")),
98  _has_relperm(hasMaterialProperty<std::vector<Real>>("PorousFlow_relative_permeability_nodal") &&
99  hasMaterialProperty<std::vector<std::vector<Real>>>(
100  "dPorousFlow_relative_permeability_nodal_dvar")),
101  _has_enthalpy(hasMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_enthalpy_nodal") &&
102  hasMaterialProperty<std::vector<std::vector<Real>>>(
103  "dPorousFlow_fluid_phase_enthalpy_nodal_dvar")),
104  _has_thermal_conductivity(
105  hasMaterialProperty<RealTensorValue>("PorousFlow_thermal_conductivity_qp") &&
106  hasMaterialProperty<std::vector<RealTensorValue>>(
107  "dPorousFlow_thermal_conductivity_qp_dvar")),
108  _has_t(hasMaterialProperty<RealGradient>("PorousFlow_grad_temperature_qp") &&
109  hasMaterialProperty<std::vector<RealGradient>>("dPorousFlow_grad_temperature_qp_dvar") &&
110  hasMaterialProperty<std::vector<Real>>("dPorousFlow_grad_temperature_qp_dgradvar")),
111 
112  _fluid_density_node(_has_density ? &getMaterialProperty<std::vector<Real>>(
113  "PorousFlow_fluid_phase_density_nodal")
114  : nullptr),
115  _dfluid_density_node_dvar(_has_density ? &getMaterialProperty<std::vector<std::vector<Real>>>(
116  "dPorousFlow_fluid_phase_density_nodal_dvar")
117  : nullptr),
118  _relative_permeability(_has_relperm ? &getMaterialProperty<std::vector<Real>>(
119  "PorousFlow_relative_permeability_nodal")
120  : nullptr),
121  _drelative_permeability_dvar(_has_relperm
122  ? &getMaterialProperty<std::vector<std::vector<Real>>>(
123  "dPorousFlow_relative_permeability_nodal_dvar")
124  : nullptr),
125  _mass_fractions(_has_mass_fraction ? &getMaterialProperty<std::vector<std::vector<Real>>>(
126  "PorousFlow_mass_frac_nodal")
127  : nullptr),
128  _dmass_fractions_dvar(_has_mass_fraction
129  ? &getMaterialProperty<std::vector<std::vector<std::vector<Real>>>>(
130  "dPorousFlow_mass_frac_nodal_dvar")
131  : nullptr),
132  _enthalpy(_has_enthalpy ? &getMaterialPropertyByName<std::vector<Real>>(
133  "PorousFlow_fluid_phase_enthalpy_nodal")
134  : nullptr),
135  _denthalpy_dvar(_has_enthalpy ? &getMaterialPropertyByName<std::vector<std::vector<Real>>>(
136  "dPorousFlow_fluid_phase_enthalpy_nodal_dvar")
137  : nullptr),
138  _thermal_conductivity(_has_thermal_conductivity ? &getMaterialProperty<RealTensorValue>(
139  "PorousFlow_thermal_conductivity_qp")
140  : nullptr),
141  _dthermal_conductivity_dvar(_has_thermal_conductivity
142  ? &getMaterialProperty<std::vector<RealTensorValue>>(
143  "dPorousFlow_thermal_conductivity_qp_dvar")
144  : nullptr),
145  _grad_t(_has_t ? &getMaterialProperty<RealGradient>("PorousFlow_grad_temperature_qp")
146  : nullptr),
147  _dgrad_t_dvar(_has_t ? &getMaterialProperty<std::vector<RealGradient>>(
148  "dPorousFlow_grad_temperature_qp_dvar")
149  : nullptr),
150  _dgrad_t_dgradvar(
151  _has_t ? &getMaterialProperty<std::vector<Real>>("dPorousFlow_grad_temperature_qp_dgradvar")
152  : nullptr)
153 {
155  paramError("mass_fraction_component",
156  "The Dictator declares that the maximum fluid component index is ",
157  _dictator.numComponents() - 1,
158  ", but you have set mass_fraction_component to ",
159  _sp,
160  ". Remember that indexing starts at 0. Please be assured that the Dictator has "
161  "noted your error.");
162 
164  mooseError("PorousFlowOutflowBC: You requested to multiply_by_density, but you have no nodal "
165  "fluid density Material");
167  mooseError("PorousFlowOutflowBC: You requested to include the relative permeability, but you "
168  "have no nodal relative permeability Material");
170  mooseError(
171  "PorousFlowOutflowBC: For flux_type = fluid, you need a nodal mass-fraction Material");
173  mooseError(
174  "PorousFlowOutflowBC: For flux_type = heat, you need a nodal fluid enthalpy Material");
176  mooseError(
177  "PorousFlowOutflowBC: For flux_type = heat, you need a thermal conductivity Material");
179  mooseError("PorousFlowOutflowBC: For flux_type = heat, you need a temperature Material");
180 }
181 
182 Real
184 {
185  Real advective_term = 0.0;
186  for (unsigned ph = 0; ph < _num_phases; ++ph)
187  advective_term -= darcy(ph) * mobility(ph) * prefactor(ph);
188 
190  return _test[_i][_qp] * advective_term * _multiplier;
191 
192  const Real conduction_term = -_normals[_qp] * ((*_thermal_conductivity)[_qp] * (*_grad_t)[_qp]);
193  return _test[_i][_qp] * (conduction_term + advective_term) * _multiplier;
194 }
195 
196 Real
198 {
199  return jac(_var.number());
200 }
201 
202 Real
204 {
205  return jac(jvar);
206 }
207 
208 Real
209 PorousFlowOutflowBC::jac(unsigned int jvar) const
210 {
212  return 0.0;
213  const unsigned int pvar = _dictator.porousFlowVariableNum(jvar);
214 
215  // For _i != _j, note:
216  // since the only non-upwinded contribution to the residual is
217  // from Darcy and thermal_conductivity, the only contribution
218  // of the residual at node _i from changing jvar at node _j is through
219  // the derivative of Darcy or thermal_conductivity
220 
221  Real advective_term_prime = 0.0;
222  for (unsigned ph = 0; ph < _num_phases; ++ph)
223  {
224  Real darcyprime =
225  _normals[_qp] *
226  (_permeability[_qp] * (_grad_phi[_j][_qp] * _dgrad_p_dgrad_var[_qp][ph][pvar] +
227  _dgrad_p_dvar[_qp][ph][pvar] * _phi[_j][_qp] -
228  _dfluid_density_qp_dvar[_qp][ph][pvar] * _phi[_j][_qp] * _gravity));
229  if (_perm_derivs)
230  {
231  darcyprime += _normals[_qp] * (_dpermeability_dvar[_qp][pvar] * _phi[_j][_qp] *
232  (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity));
233  for (const auto i : make_range(Moose::dim))
234  darcyprime +=
235  _normals[_qp] * (_dpermeability_dgradvar[_qp][i][pvar] * _grad_phi[_j][_qp](i) *
236  (_grad_p[_qp][ph] - _fluid_density_qp[_qp][ph] * _gravity));
237  }
238  if (_i != _j)
239  advective_term_prime -= prefactor(ph) * mobility(ph) * darcyprime;
240  else
241  {
242  const Real dar = darcy(ph);
243 
244  Real mob = 1.0 / _fluid_viscosity[_i][ph];
245  Real mobprime =
246  -_dfluid_viscosity_dvar[_i][ph][pvar] / Utility::pow<2>(_fluid_viscosity[_i][ph]);
248  {
249  const Real densityprime = (*_dfluid_density_node_dvar)[_i][ph][pvar];
250  mobprime = densityprime * mob + (*_fluid_density_node)[_i][ph] * mobprime;
251  mob *= (*_fluid_density_node)[_i][ph];
252  }
253  if (_include_relperm)
254  {
255  const Real relpermprime = (*_drelative_permeability_dvar)[_i][ph][pvar];
256  mobprime = relpermprime * mob + (*_relative_permeability)[_i][ph] * mobprime;
257  mob *= (*_relative_permeability)[_i][ph];
258  }
259 
260  const Real pre = prefactor(ph);
261  const Real preprime =
262  (_flux_type == FluxTypeChoiceEnum::FLUID ? (*_dmass_fractions_dvar)[_i][ph][_sp][pvar]
263  : (*_denthalpy_dvar)[_i][ph][pvar]);
264 
265  advective_term_prime -= preprime * mob * dar + pre * mobprime * dar + pre * mob * darcyprime;
266  }
267  }
269  return _test[_i][_qp] * advective_term_prime * _multiplier;
270 
271  const Real conduction_term_prime =
272  -_normals[_qp] *
273  ((*_dthermal_conductivity_dvar)[_qp][pvar] * (*_grad_t)[_qp] +
274  (*_thermal_conductivity)[_qp] * (*_dgrad_t_dvar)[_qp][pvar]) *
275  _phi[_j][_qp] -
276  _normals[_qp] *
277  ((*_thermal_conductivity)[_qp] * (*_dgrad_t_dgradvar)[_qp][pvar] * _grad_phi[_j][_qp]);
278  return _test[_i][_qp] * (conduction_term_prime + advective_term_prime) * _multiplier;
279 }
280 
281 Real
282 PorousFlowOutflowBC::darcy(unsigned ph) const
283 {
284  return _normals[_qp] *
286 }
287 
288 Real
290 {
291  return (_multiply_by_density ? (*_fluid_density_node)[_i][ph] : 1.0) *
292  (_include_relperm ? (*_relative_permeability)[_i][ph] : 1.0) / _fluid_viscosity[_i][ph];
293 }
294 
295 Real
297 {
299  : (*_enthalpy)[_i][ph]);
300 }
const VariableTestValue & _test
Real jac(unsigned int jvar) const
Derivative of residual with respect to the jvar variable.
unsigned int _j
bool notPorousFlowVariable(unsigned int moose_var_num) const
Returns true if moose_var_num is not a porous flow variabe.
const MooseArray< Point > & _normals
const MaterialProperty< std::vector< std::vector< RealTensorValue > > > & _dpermeability_dgradvar
d(permeabiity)/d(grad(PorousFlow variable))
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
unsigned int number() const
const bool _perm_derivs
Flag indicating whether to include derivatives of the permeability in the Jacobian.
const MaterialProperty< std::vector< std::vector< Real > > > & _dgrad_p_dgrad_var
Derivative of Grad porepressure in each phase wrt grad(PorousFlow variables)
const MaterialProperty< std::vector< Real > > *const _enthalpy
Enthalpy of each phase.
const MaterialProperty< std::vector< std::vector< Real > > > *const _mass_fractions
Mass fraction of each component in each phase.
const unsigned _num_phases
Number of phases in the simulation.
unsigned int numComponents() const
The number of fluid components.
static InputParameters validParams()
unsigned int _i
static constexpr std::size_t dim
const PorousFlowDictator & _dictator
PorousFlowDictator UserObject.
const MaterialProperty< std::vector< Real > > & _fluid_density_qp
Fluid density for each phase (at the qp)
virtual Real computeQpOffDiagJacobian(unsigned int jvar) override
const VariablePhiValue & _phi
enum PorousFlowOutflowBC::FluxTypeChoiceEnum _flux_type
virtual Real computeQpJacobian() override
void addRequiredParam(const std::string &name, const std::string &doc_string)
unsigned int _qp
const bool _has_mass_fraction
Whether there is a mass_frac_nodal Material.
Applies a flux to a boundary such that fluid or heat will flow freely out of the boundary.
const VariablePhiGradient & _grad_phi
const RealVectorValue _gravity
Gravitational acceleration.
TensorValue< Real > RealTensorValue
const bool _has_thermal_conductivity
Whether there is a thermal_conductivity_qp Material.
const bool _include_relperm
Whether to multiply the Darcy flux by the relative permeability.
PorousFlowOutflowBC(const InputParameters &parameters)
FluxTypeChoiceEnum
Indicates the type of flux that this BC will apply.
void paramError(const std::string &param, Args... args) const
const MaterialProperty< std::vector< RealTensorValue > > & _dpermeability_dvar
d(permeabiity)/d(PorousFlow variable)
const bool _has_t
Whether there is a grad_temp Material.
const MaterialProperty< std::vector< Real > > *const _fluid_density_node
Fluid density for each phase (at the node)
Real darcy(unsigned ph) const
Darcy contribution to the outflowBC.
const MaterialProperty< std::vector< std::vector< Real > > > & _dfluid_density_qp_dvar
Derivative of the fluid density for each phase wrt PorousFlow variables (at the qp) ...
MooseVariable & _var
static InputParameters validParams()
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const bool _has_density
Whether there is a fluid_phase_density_nodal Material.
Real prefactor(unsigned ph) const
Either mass_fraction or enthalpy, depending on _flux_type.
This holds maps between the nonlinear variables used in a PorousFlow simulation and the variable numb...
const MaterialProperty< std::vector< std::vector< Real > > > & _dfluid_viscosity_dvar
Derivative of the fluid viscosity for each phase wrt PorousFlow variables.
IntRange< T > make_range(T beg, T end)
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
const Real _multiplier
Multiply the flux by this quantity. This is mainly used for testing purposes, for instance...
const MaterialProperty< std::vector< Real > > & _fluid_viscosity
Viscosity of each phase.
const MaterialProperty< std::vector< std::vector< RealGradient > > > & _dgrad_p_dvar
Derivative of Grad porepressure in each phase wrt PorousFlow variables.
unsigned int porousFlowVariableNum(unsigned int moose_var_num) const
The PorousFlow variable number.
const bool _has_enthalpy
Whether there is an enthalpy Material.
const bool _has_relperm
Whether there is a relative_permeability_nodal Material.
const MaterialProperty< RealTensorValue > & _permeability
Permeability of porous material.
const unsigned int _sp
The fluid component number (only used if _flux_type==FLUID))
const MaterialProperty< RealTensorValue > *const _thermal_conductivity
Thermal_Conductivity of porous material.
registerMooseObject("PorousFlowApp", PorousFlowOutflowBC)
Real mobility(unsigned ph) const
Mobility contribution to the outflowBC.
virtual Real computeQpResidual() override
const bool _multiply_by_density
Whether to multiply the Darcy flux by the fluid density. This is automatically set to true if _flux_t...
const MaterialProperty< std::vector< RealGradient > > & _grad_p
Gradient of the pore pressure in each phase.
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)