11 #include "RotationMatrix.h"
19 InputParameters params = validParams<DiracKernel>();
20 params.addRequiredParam<FunctionName>(
22 "If zero then borehole does nothing. If positive the borehole acts as a sink "
23 "(production well) for porepressure > borehole pressure, and does nothing "
24 "otherwise. If negative the borehole acts as a source (injection well) for "
25 "porepressure < borehole pressure, and does nothing otherwise. The flow rate "
26 "to/from the borehole is multiplied by |character|, so usually character = +/- "
27 "1, but you can specify other quantities to provide an overall scaling to the "
29 params.addRequiredParam<Real>(
"bottom_pressure",
"Pressure at the bottom of the borehole");
30 params.addRequiredParam<RealVectorValue>(
32 "(fluid_density*gravitational_acceleration) as a vector pointing downwards. "
33 "Note that the borehole pressure at a given z position is bottom_pressure + "
34 "unit_weight*(p - p_bottom), where p=(x,y,z) and p_bottom=(x,y,z) of the "
35 "bottom point of the borehole. If you don't want bottomhole pressure to vary "
36 "in the borehole just set unit_weight=0. Typical value is = (0,0,-1E4)");
37 params.addRequiredParam<std::string>(
39 "The file containing the borehole radii and coordinates of the point sinks "
40 "that approximate the borehole. Each line in the file must contain a "
41 "space-separated radius and coordinate. Ie r x y z. The last point in the "
42 "file is defined as the borehole bottom, where the borehole pressure is "
43 "bottom_pressure. If your file contains just one point, you must also specify "
44 "the borehole_length and borehole_direction. Note that you will get "
45 "segementation faults if your points do not lie within your mesh!");
46 params.addRequiredParam<UserObjectName>(
48 "User Object of type=RichardsSumQuantity in which to place the total "
49 "outflow from the borehole for each time step.");
50 params.addParam<Real>(
"re_constant",
52 "The dimensionless constant used in evaluating the borehole effective "
53 "radius. This depends on the meshing scheme. Peacemann "
54 "finite-difference calculations give 0.28, while for rectangular finite "
55 "elements the result is closer to 0.1594. (See Eqn(4.13) of Z Chen, Y "
56 "Zhang, Well flow models for various numerical methods, Int J Num "
57 "Analysis and Modeling, 3 (2008) 375-388.)");
58 params.addParam<Real>(
"well_constant",
60 "Usually this is calculated internally from the element geometry, the "
61 "local borehole direction and segment length, and the permeability. "
62 "However, if this parameter is given as a positive number then this "
63 "number is used instead of the internal calculation. This speeds up "
64 "computation marginally. re_constant becomes irrelevant");
65 params.addRangeCheckedParam<Real>(
69 "Borehole length. Note this is only used if there is only one point in the point_file.");
70 params.addParam<RealVectorValue>(
72 RealVectorValue(0, 0, 1),
73 "Borehole direction. Note this is only used if there is only one point in the point_file.");
74 params.addClassDescription(
"Approximates a borehole in the mesh using the Peaceman approach, ie "
75 "using a number of point sinks with given radii whose positions are "
81 : DiracKernel(parameters),
82 _re_constant(getParam<Real>(
"re_constant")),
83 _well_constant(getParam<Real>(
"well_constant")),
84 _borehole_length(getParam<Real>(
"borehole_length")),
85 _borehole_direction(getParam<RealVectorValue>(
"borehole_direction")),
86 _point_file(getParam<std::string>(
"point_file")),
87 _character(getFunction(
"character")),
88 _p_bot(getParam<Real>(
"bottom_pressure")),
89 _unit_weight(getParam<RealVectorValue>(
"unit_weight")),
99 mooseError(
"Error opening file '" +
_point_file +
"' from a Peaceman-type Borehole.");
102 std::vector<Real> scratch;
105 if (scratch.size() >= 2)
107 _rs.push_back(scratch[0]);
108 _xs.push_back(scratch[1]);
109 if (scratch.size() >= 3)
110 _ys.push_back(scratch[2]);
113 if (scratch.size() >= 4)
114 _zs.push_back(scratch[3]);
122 const int num_pts =
_zs.size();
129 for (
unsigned int i = 0; i + 1 <
_xs.size(); ++i)
135 mooseError(
"Peaceman-type borehole has a zero-segment length at (x,y,z) = ",
148 for (
unsigned int i = 0; i + 1 <
_xs.size(); ++i)
150 const RealVectorValue v2(
_xs[i + 1] -
_xs[i],
_ys[i + 1] -
_ys[i],
_zs[i + 1] -
_zs[i]);
164 if (getline(ifs, line))
169 std::istringstream iss(line);
189 for (
unsigned int i = 0; i <
_zs.size(); i++)
190 addPoint(Point(
_xs[i],
_ys[i],
_zs[i]), i);
195 const RealTensorValue & rot,
196 const Real & half_len,
208 const RealTensorValue rot_perm = (rot * perm) * rot.transpose();
209 const Real trace2D = rot_perm(0, 0) + rot_perm(1, 1);
210 const Real det2D = rot_perm(0, 0) * rot_perm(1, 1) - rot_perm(0, 1) * rot_perm(1, 0);
211 const Real sq = std::sqrt(std::max(0.25 * trace2D * trace2D - det2D,
213 const Real eig_val1 = 0.5 * trace2D + sq;
214 const Real eig_val2 = 0.5 * trace2D - sq;
215 RealVectorValue eig_vec1, eig_vec2;
216 if (sq > std::abs(trace2D) * 1E-7)
219 if (rot_perm(1, 0) != 0)
221 eig_vec1(0) = eig_val1 - rot_perm(1, 1);
222 eig_vec1(1) = rot_perm(1, 0);
223 eig_vec2(0) = eig_val2 - rot_perm(1, 1);
224 eig_vec2(1) = rot_perm(1, 0);
226 else if (rot_perm(0, 1) != 0)
228 eig_vec1(0) = rot_perm(0, 1);
229 eig_vec1(1) = eig_val1 - rot_perm(0, 0);
230 eig_vec2(0) = rot_perm(0, 1);
231 eig_vec2(1) = eig_val2 - rot_perm(0, 0);
246 eig_vec1 = rot.transpose() * eig_vec1;
247 eig_vec1 /= std::sqrt(eig_vec1 * eig_vec1);
248 eig_vec2 = rot.transpose() * eig_vec2;
249 eig_vec2 /= std::sqrt(eig_vec2 * eig_vec2);
253 Real max1 = eig_vec1 * ele->point(0);
254 Real max2 = eig_vec2 * ele->point(0);
258 for (
unsigned int i = 1; i < ele->n_nodes(); i++)
260 proj = eig_vec1 * ele->point(i);
261 max1 = (max1 < proj) ? proj : max1;
262 min1 = (min1 < proj) ? min1 : proj;
264 proj = eig_vec2 * ele->point(i);
265 max2 = (max2 < proj) ? proj : max2;
266 min2 = (min2 < proj) ? min2 : proj;
268 const Real ll1 = max1 - min1;
269 const Real ll2 = max2 - min2;
272 std::sqrt(eig_val2 / eig_val1) *
std::pow(ll1, 2)) /
273 (
std::pow(eig_val1 / eig_val2, 0.25) +
std::pow(eig_val2 / eig_val1, 0.25));
275 const Real effective_perm = std::sqrt(det2D);
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);