21 "If zero then borehole does nothing. If positive the borehole acts as a sink " 22 "(production well) for porepressure > borehole pressure, and does nothing " 23 "otherwise. If negative the borehole acts as a source (injection well) for " 24 "porepressure < borehole pressure, and does nothing otherwise. The flow rate " 25 "to/from the borehole is multiplied by |character|, so usually character = +/- " 26 "1, but you can specify other quantities to provide an overall scaling to the " 31 "(fluid_density*gravitational_acceleration) as a vector pointing downwards. " 32 "Note that the borehole pressure at a given z position is bottom_pressure + " 33 "unit_weight*(p - p_bottom), where p=(x,y,z) and p_bottom=(x,y,z) of the " 34 "bottom point of the borehole. If you don't want bottomhole pressure to vary " 35 "in the borehole just set unit_weight=0. Typical value is = (0,0,-1E4)");
38 "The file containing the borehole radii and coordinates of the point sinks " 39 "that approximate the borehole. Each line in the file must contain a " 40 "space-separated radius and coordinate. Ie r x y z. The last point in the " 41 "file is defined as the borehole bottom, where the borehole pressure is " 42 "bottom_pressure. If your file contains just one point, you must also specify " 43 "the borehole_length and borehole_direction. Note that you will get " 44 "segementation faults if your points do not lie within your mesh!");
47 "User Object of type=RichardsSumQuantity in which to place the total " 48 "outflow from the borehole for each time step.");
51 "The dimensionless constant used in evaluating the borehole effective " 52 "radius. This depends on the meshing scheme. Peacemann " 53 "finite-difference calculations give 0.28, while for rectangular finite " 54 "elements the result is closer to 0.1594. (See Eqn(4.13) of Z Chen, Y " 55 "Zhang, Well flow models for various numerical methods, Int J Num " 56 "Analysis and Modeling, 3 (2008) 375-388.)");
59 "Usually this is calculated internally from the element geometry, the " 60 "local borehole direction and segment length, and the permeability. " 61 "However, if this parameter is given as a positive number then this " 62 "number is used instead of the internal calculation. This speeds up " 63 "computation marginally. re_constant becomes irrelevant");
68 "Borehole length. Note this is only used if there is only one point in the point_file.");
72 "Borehole direction. Note this is only used if there is only one point in the point_file.");
73 params.
addClassDescription(
"Approximates a borehole in the mesh using the Peaceman approach, ie " 74 "using a number of point sinks with given radii whose positions are " 81 _re_constant(getParam<
Real>(
"re_constant")),
82 _well_constant(getParam<
Real>(
"well_constant")),
83 _borehole_length(getParam<
Real>(
"borehole_length")),
85 _point_file(getParam<
std::string>(
"point_file")),
86 _character(getFunction(
"character")),
87 _p_bot(getParam<
Real>(
"bottom_pressure")),
101 std::vector<Real> scratch;
104 if (scratch.size() >= 2)
106 _rs.push_back(scratch[0]);
107 _xs.push_back(scratch[1]);
108 if (scratch.size() >= 3)
109 _ys.push_back(scratch[2]);
112 if (scratch.size() >= 4)
113 _zs.push_back(scratch[3]);
121 const int num_pts =
_zs.size();
128 for (
unsigned int i = 0; i + 1 <
_xs.size(); ++i)
134 mooseError(
"Peaceman-type borehole has a zero-segment length at (x,y,z) = ",
147 for (
unsigned int i = 0; i + 1 <
_xs.size(); ++i)
163 if (getline(ifs, line))
168 std::istringstream iss(line);
188 for (
unsigned int i = 0; i <
_zs.size(); i++)
195 const Real & half_len,
208 const Real trace2D = rot_perm(0, 0) + rot_perm(1, 1);
209 const Real det2D = rot_perm(0, 0) * rot_perm(1, 1) - rot_perm(0, 1) * rot_perm(1, 0);
210 const Real sq =
std::sqrt(std::max(0.25 * trace2D * trace2D - det2D,
212 const Real eig_val1 = 0.5 * trace2D + sq;
213 const Real eig_val2 = 0.5 * trace2D - sq;
218 if (rot_perm(1, 0) != 0)
220 eig_vec1(0) = eig_val1 - rot_perm(1, 1);
221 eig_vec1(1) = rot_perm(1, 0);
222 eig_vec2(0) = eig_val2 - rot_perm(1, 1);
223 eig_vec2(1) = rot_perm(1, 0);
225 else if (rot_perm(0, 1) != 0)
227 eig_vec1(0) = rot_perm(0, 1);
228 eig_vec1(1) = eig_val1 - rot_perm(0, 0);
229 eig_vec2(0) = rot_perm(0, 1);
230 eig_vec2(1) = eig_val2 - rot_perm(0, 0);
245 eig_vec1 = rot.transpose() * eig_vec1;
246 eig_vec1 /=
std::sqrt(eig_vec1 * eig_vec1);
247 eig_vec2 = rot.transpose() * eig_vec2;
248 eig_vec2 /=
std::sqrt(eig_vec2 * eig_vec2);
252 Real max1 = eig_vec1 * ele->point(0);
253 Real max2 = eig_vec2 * ele->point(0);
257 for (
unsigned int i = 1; i < ele->n_nodes(); i++)
259 proj = eig_vec1 * ele->point(i);
260 max1 = (max1 < proj) ? proj : max1;
261 min1 = (min1 < proj) ? min1 : proj;
263 proj = eig_vec2 * ele->point(i);
264 max2 = (max2 < proj) ? proj : max2;
265 min2 = (min2 < proj) ? min2 : proj;
267 const Real ll1 = max1 - min1;
268 const Real ll2 = max2 - min2;
273 (
std::pow(eig_val1 / eig_val2, 0.25) +
std::pow(eig_val2 / eig_val1, 0.25));
277 const Real halfPi = acos(0.0);
280 mooseError(
"The effective element size (about 0.2-times-true-ele-size) for an element " 281 "containing a Peaceman-type borehole must be (much) larger than the borehole radius " 282 "for the Peaceman formulation to be correct. Your element has effective size ",
284 " and the borehole radius is ",
288 return 4 * halfPi * effective_perm * half_len / std::log(r0 / rad);
const Real _well_constant
well constant
const RealVectorValue _borehole_direction
borehole direction. Note this is only used if there is only one borehole point
Sums into _total This is used, for instance, to record the total mass flowing into a borehole...
const Real _re_constant
borehole constant
PeacemanBorehole(const InputParameters ¶meters)
Real wellConstant(const RealTensorValue &perm, const RealTensorValue &rot, const Real &half_len, const Elem *ele, const Real &rad)
Calculates Peaceman's form of the borehole well constant Z Chen, Y Zhang, Well flow models for variou...
std::vector< Real > _rs
radii of the borehole
void addPoint(const Elem *elem, Point p, unsigned id=libMesh::invalid_uint)
bool parseNextLineReals(std::ifstream &ifs, std::vector< Real > &myvec)
reads a space-separated line of floats from ifs and puts in myvec
ADRealEigenVector< T, D, asd > sqrt(const ADRealEigenVector< T, D, asd > &)
std::vector< Real > _xs
x points of the borehole
std::vector< Real > _ys
y points of the borehole
static InputParameters validParams()
Creates a new PeacemanBorehole This reads the file containing the lines of the form radius x y z that...
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
TensorValue< Real > RealTensorValue
Real f(Real x)
Test function for Brents method.
void zero()
sets _total = 0
RichardsSumQuantity & _total_outflow_mass
This is used to hold the total fluid flowing into the borehole Hence, it is positive for production w...
GenericRealTensorValue< is_ad > rotVecToZ(GenericRealVectorValue< is_ad > vec)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Real _borehole_length
borehole length. Note this is only used if there is only one borehole point
virtual void addPoints()
Add Dirac Points to the borehole.
const std::string _point_file
File defining the geometry of the borehole.
void mooseError(Args &&... args) const
Point _bottom_point
the bottom point of the borehole (where bottom_pressure is defined)
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)
std::vector< Real > _zs
z points of borehole
MooseUnits pow(const MooseUnits &, int)
static InputParameters validParams()