www.mooseframework.org
Q2PBorehole.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "Q2PBorehole.h"
11 #include "RotationMatrix.h"
12 
13 registerMooseObject("RichardsApp", Q2PBorehole);
14 
17 {
19  params.addRequiredParam<UserObjectName>(
20  "fluid_density",
21  "A RichardsDensity UserObject that defines the fluid density as a function of pressure.");
22  params.addRequiredParam<UserObjectName>(
23  "fluid_relperm",
24  "A RichardsRelPerm UserObject (eg RichardsRelPermPower) that defines the "
25  "fluid relative permeability as a function of the saturation Variable.");
26  params.addRequiredCoupledVar("other_var",
27  "The other variable in the 2-phase system. If "
28  "Variable=porepressure, the other_var=saturation, and "
29  "vice-versa.");
30  params.addRequiredParam<bool>("var_is_porepressure",
31  "This flag is needed to correctly calculate the Jacobian entries. "
32  "If set to true, this Sink will extract fluid from the phase with "
33  "porepressure as its Variable (usually the liquid phase). If set "
34  "to false, this Sink will extract fluid from the phase with "
35  "saturation as its variable (usually the gas phase)");
36  params.addRequiredParam<Real>("fluid_viscosity", "The fluid dynamic viscosity");
37  params.addClassDescription("Approximates a borehole in the mesh with given bottomhole pressure, "
38  "and radii using a number of point sinks whose positions are read "
39  "from a file. This DiracKernel is for use by Q2P models");
40  return params;
41 }
42 
44  : PeacemanBorehole(parameters),
45  _density(getUserObject<RichardsDensity>("fluid_density")),
46  _relperm(getUserObject<RichardsRelPerm>("fluid_relperm")),
47  _other_var_nodal(coupledDofValues("other_var")),
48  _other_var_num(coupled("other_var")),
49  _var_is_pp(getParam<bool>("var_is_porepressure")),
50  _viscosity(getParam<Real>("fluid_viscosity")),
51  _permeability(getMaterialProperty<RealTensorValue>("permeability")),
52  _num_nodes(0),
53  _pp(0),
54  _sat(0),
55  _mobility(0),
56  _dmobility_dp(0),
57  _dmobility_ds(0)
58 {
59 }
60 
61 void
63 {
65 
66  // set _pp and _sat variables
67  _pp.resize(_num_nodes);
68  _sat.resize(_num_nodes);
69  if (_var_is_pp)
70  {
71  for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
72  {
73  _pp[nodenum] = _var.dofValues()[nodenum];
74  _sat[nodenum] = _other_var_nodal[nodenum];
75  }
76  }
77  else
78  {
79  for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
80  {
81  _pp[nodenum] = _other_var_nodal[nodenum];
82  _sat[nodenum] = _var.dofValues()[nodenum];
83  }
84  }
85 
86  Real density;
87  Real ddensity_dp;
88  Real relperm;
89  Real drelperm_ds;
90  _mobility.resize(_num_nodes);
91  _dmobility_dp.resize(_num_nodes);
92  _dmobility_ds.resize(_num_nodes);
93  for (unsigned int nodenum = 0; nodenum < _num_nodes; ++nodenum)
94  {
95  density = _density.density(_pp[nodenum]);
96  ddensity_dp = _density.ddensity(_pp[nodenum]);
97  relperm = _relperm.relperm(_sat[nodenum]);
98  drelperm_ds = _relperm.drelperm(_sat[nodenum]);
99  _mobility[nodenum] = density * relperm / _viscosity;
100  _dmobility_dp[nodenum] = ddensity_dp * relperm / _viscosity;
101  _dmobility_ds[nodenum] = density * drelperm_ds / _viscosity;
102  }
103 }
104 
105 void
107 {
110 }
111 
112 Real
114 {
115  const Real character = _character.value(_t, _q_point[_qp]);
116  if (character == 0.0)
117  return 0.0;
118 
119  const Real bh_pressure =
120  _p_bot +
121  _unit_weight *
122  (_q_point[_qp] -
123  _bottom_point); // really want to use _q_point instaed of _current_point, i think?!
124 
125  // Get the ID we initially assigned to this point
126  const unsigned current_dirac_ptid = currentPointCachedID();
127 
128  // If getting the ID failed, fall back to the old bodge!
129  // if (current_dirac_ptid == libMesh::invalid_uint)
130  // current_dirac_ptid = (_zs.size() > 2) ? 1 : 0;
131 
132  Real outflow(0.0); // this is the flow rate from porespace out of the system
133 
134  Real wc(0.0);
135  if (current_dirac_ptid > 0)
136  // contribution from half-segment "behind" this point (must have >1 point for
137  // current_dirac_ptid>0)
138  {
139  wc = wellConstant(_permeability[0],
140  _rot_matrix[current_dirac_ptid - 1],
141  _half_seg_len[current_dirac_ptid - 1],
143  _rs[current_dirac_ptid]);
144  if ((character < 0.0 && _pp[_i] < bh_pressure) || (character > 0.0 && _pp[_i] > bh_pressure))
145  // injection, so outflow<0 || // production, so outflow>0
146  outflow +=
147  _test[_i][_qp] * std::abs(character) * wc * _mobility[_i] * (_pp[_i] - bh_pressure);
148  }
149 
150  if (current_dirac_ptid + 1 < _zs.size() || _zs.size() == 1)
151  // contribution from half-segment "ahead of" this point, or we only have one point
152  {
153  wc = wellConstant(_permeability[0],
154  _rot_matrix[current_dirac_ptid],
155  _half_seg_len[current_dirac_ptid],
157  _rs[current_dirac_ptid]);
158  if ((character < 0.0 && _pp[_i] < bh_pressure) || (character > 0.0 && _pp[_i] > bh_pressure))
159  // injection, so outflow<0 || // production, so outflow>0
160  outflow +=
161  _test[_i][_qp] * std::abs(character) * wc * _mobility[_i] * (_pp[_i] - bh_pressure);
162  }
163 
165  outflow * _dt); // this is not thread safe, but DiracKernel's aren't currently threaded
166  return outflow;
167 }
168 
169 void
171 {
174 }
175 
176 Real
178 {
179  return jac(_var.number());
180 }
181 
182 Real
184 {
185  if (jvar == _other_var_num || jvar == _var.number())
186  return jac(jvar);
187  return 0.0;
188 }
189 
190 Real
191 Q2PBorehole::jac(unsigned int jvar)
192 {
193  if (_i != _j)
194  return 0.0;
195 
196  const Real character = _character.value(_t, _q_point[_qp]);
197  if (character == 0.0)
198  return 0.0;
199 
200  const Real bh_pressure =
201  _p_bot +
202  _unit_weight *
203  (_q_point[_qp] -
204  _bottom_point); // really want to use _q_point instaed of _current_point, i think?!
205 
206  const Real phi = 1;
207 
208  // Get the ID we initially assigned to this point
209  const unsigned current_dirac_ptid = currentPointCachedID();
210 
211  // If getting the ID failed, fall back to the old bodge!
212  // if (current_dirac_ptid == libMesh::invalid_uint)
213  // current_dirac_ptid = (_zs.size() > 2) ? 1 : 0;
214 
215  Real outflowp(0.0);
216 
217  const bool deriv_wrt_pp =
218  (_var_is_pp && (jvar == _var.number())) || (!_var_is_pp && (jvar == _other_var_num));
219 
220  Real wc(0.0);
221  if (current_dirac_ptid > 0)
222  // contribution from half-segment "behind" this point
223  {
224  wc = wellConstant(_permeability[0],
225  _rot_matrix[current_dirac_ptid - 1],
226  _half_seg_len[current_dirac_ptid - 1],
228  _rs[current_dirac_ptid]);
229  if ((character < 0.0 && _pp[_i] < bh_pressure) || (character > 0.0 && _pp[_i] > bh_pressure))
230  {
231  // injection, so outflow<0 || // production, so outflow>0
232  if (deriv_wrt_pp)
233  outflowp += std::abs(character) * wc *
234  (_mobility[_i] * phi + _dmobility_dp[_i] * phi * (_pp[_i] - bh_pressure));
235  else
236  outflowp += std::abs(character) * wc * _dmobility_ds[_i] * phi * (_pp[_i] - bh_pressure);
237  }
238  }
239 
240  if (current_dirac_ptid < _zs.size() - 1 || _zs.size() == 1)
241  // contribution from half-segment "ahead of" this point
242  {
243  wc = wellConstant(_permeability[0],
244  _rot_matrix[current_dirac_ptid],
245  _half_seg_len[current_dirac_ptid],
247  _rs[current_dirac_ptid]);
248  if ((character < 0.0 && _pp[_i] < bh_pressure) || (character > 0.0 && _pp[_i] > bh_pressure))
249  {
250  // injection, so outflow<0 || // production, so outflow>0
251  if (deriv_wrt_pp)
252  outflowp += std::abs(character) * wc *
253  (_mobility[_i] * phi + _dmobility_dp[_i] * phi * (_pp[_i] - bh_pressure));
254  else
255  outflowp += std::abs(character) * wc * _dmobility_ds[_i] * phi * (_pp[_i] - bh_pressure);
256  }
257  }
258 
259  return _test[_i][_qp] * outflowp;
260 }
unsigned int _num_nodes
number of nodes in this element.
Definition: Q2PBorehole.h:89
const RichardsRelPerm & _relperm
fluid relative permeability
Definition: Q2PBorehole.h:71
const MooseArray< Point > & _q_point
virtual Real drelperm(Real seff) const =0
derivative of relative permeability wrt effective saturation This must be over-ridden in your derived...
virtual Real ddensity(Real p) const =0
derivative of fluid density wrt porepressure This must be over-ridden in derived classes to provide a...
std::vector< Real > _dmobility_dp
nodal d(mobility)/d(porepressure)
Definition: Q2PBorehole.h:101
Real wellConstant(const RealTensorValue &perm, const RealTensorValue &rot, const Real &half_len, const Elem *ele, const Real &rad)
Calculates Peaceman&#39;s form of the borehole well constant Z Chen, Y Zhang, Well flow models for variou...
unsigned int number() const
Base class for Richards relative permeability classes that provide relative permeability as a functio...
const unsigned int _other_var_num
the variable number of the other variable
Definition: Q2PBorehole.h:77
registerMooseObject("RichardsApp", Q2PBorehole)
std::vector< Real > _rs
radii of the borehole
const OutputTools< T >::VariableTestValue & _test
virtual Real computeQpResidual()
Computes the Qp residual.
Definition: Q2PBorehole.C:113
static const std::string density
Definition: NS.h:33
unsigned currentPointCachedID()
const VariableValue & _other_var_nodal
the other variable in the 2-phase system (this is saturation if Variable=porepressure, and viceversa)
Definition: Q2PBorehole.h:74
Approximates a borehole by a sequence of Dirac Points.
static InputParameters validParams()
Creates a new PeacemanBorehole This reads the file containing the lines of the form radius x y z that...
std::vector< Real > _mobility
nodal mobility
Definition: Q2PBorehole.h:98
Q2PBorehole(const InputParameters &parameters)
Definition: Q2PBorehole.C:43
virtual void computeResidual()
Computes the residual.
Definition: Q2PBorehole.C:106
void addRequiredParam(const std::string &name, const std::string &doc_string)
void prepareNodalValues()
calculates the nodal values of pressure, mobility, and derivatives thereof
Definition: Q2PBorehole.C:62
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
virtual Real density(Real p) const =0
fluid density as a function of porepressure This must be over-ridden in derived classes to provide an...
TensorValue< Real > RealTensorValue
virtual void computeJacobian()
Computes the Jacobian.
Definition: Q2PBorehole.C:170
static InputParameters validParams()
Creates a new Q2PBorehole This sets all the variables, but also reads the file containing the lines o...
Definition: Q2PBorehole.C:16
const Real _viscosity
viscosity
Definition: Q2PBorehole.h:83
std::vector< Real > _sat
nodal saturation
Definition: Q2PBorehole.h:95
const RealVectorValue _unit_weight
unit weight of fluid in borehole (for calculating bottomhole pressure at each Dirac Point) ...
MooseVariableField< T > & _var
virtual Real computeQpJacobian()
Computes the diagonal part of the jacobian.
Definition: Q2PBorehole.C:177
virtual Real relperm(Real seff) const =0
relative permeability as a function of effective saturation This must be over-ridden in your derived ...
virtual const DoFValue & dofValues() const =0
void add(Real contrib)
adds contrib to _total
RichardsSumQuantity & _total_outflow_mass
This is used to hold the total fluid flowing into the borehole Hence, it is positive for production w...
const RichardsDensity & _density
fluid density
Definition: Q2PBorehole.h:68
const Elem *const & _current_elem
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
const Real _p_bot
bottomhole pressure of borehole
std::vector< Real > _dmobility_ds
nodal d(mobility)/d(saturation)
Definition: Q2PBorehole.h:104
const bool _var_is_pp
whether the Variable for this BC is porepressure or not
Definition: Q2PBorehole.h:80
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
unsigned int _j
Approximates a borehole by a sequence of Dirac Points.
Definition: Q2PBorehole.h:21
unsigned int _qp
virtual void computeJacobian() override
const MaterialProperty< RealTensorValue > & _permeability
permeability
Definition: Q2PBorehole.h:86
Real jac(unsigned int jvar)
Calculates Jacobian.
Definition: Q2PBorehole.C:191
void addClassDescription(const std::string &doc_string)
Point _bottom_point
the bottom point of the borehole (where bottom_pressure is defined)
Base class for fluid density as a function of porepressure The functions density, ddensity and d2dens...
std::vector< RealTensorValue > _rot_matrix
rotation matrix used in well_constant calculation
std::vector< Real > _half_seg_len
0.5*(length of polyline segments between points)
virtual Real value(Real t, const Point &p) const
std::vector< Real > _zs
z points of borehole
unsigned int _i
std::vector< Real > _pp
nodal porepressure
Definition: Q2PBorehole.h:92
virtual Real computeQpOffDiagJacobian(unsigned int jvar)
Computes the off-diagonal part of the jacobian.
Definition: Q2PBorehole.C:183
virtual void computeResidual() override
const Function & _character
If positive then the borehole acts as a sink (producion well) for porepressure > borehole pressure...