OpenCAEPoro  v0.5.0
A simulator for multicomponent porous media flow
AllWells.cpp
Go to the documentation of this file.
1 
12 #include "AllWells.hpp"
13 
15 // General
17 
18 void AllWells::InputParam(const ParamWell& paramWell, const ParamOutput& output_param)
19 {
21 
22  for (auto& s : paramWell.solSet) {
23  solvents.push_back(s);
24  }
25 
26  Psurf = paramWell.Psurf;
27  Tsurf = paramWell.Tsurf;
28 
29  numWell = paramWell.well.size();
30  wells.resize(numWell);
31  USI t = paramWell.criticalTime.size();
32  vector<USI> wellOptTime;
33  for (USI w = 0; w < numWell; w++) {
34  wells[w].name = paramWell.well[w].name;
35  wells[w].group = paramWell.well[w].group;
36  wells[w].depth = paramWell.well[w].depth;
37  wells[w].I = paramWell.well[w].I - 1;
38  wells[w].J = paramWell.well[w].J - 1;
39  wells[w].InputPerfo(paramWell.well[w]);
40  wells[w].Psurf = Psurf;
41  wells[w].Tsurf = Tsurf;
42  wells[w].ifUseUnweight = paramWell.well[w].ifUseUnweight;
43  // opt
44  wells[w].optSet.resize(t);
45 
46  // If identical optParam.d occurs, use the last one
47  vector<WellOptPair> tmpOptParam;
48  const USI n0 = paramWell.well[w].optParam.size();
49  for (USI i = 0; i < n0 - 1; i++) {
50  if (paramWell.well[w].optParam[i].d !=
51  paramWell.well[w].optParam[i + 1].d) {
52  tmpOptParam.push_back(paramWell.well[w].optParam[i]);
53  }
54  }
55  tmpOptParam.push_back(paramWell.well[w].optParam.back());
56 
57  const USI n = tmpOptParam.size();
58  wellOptTime.clear();
59  wellOptTime.resize(n + 1);
60  for (USI i = 0; i < n; i++) {
61  wellOptTime[i] = tmpOptParam[i].d;
62  }
63  wellOptTime.back() = t;
64  for (USI i = 0; i < n; i++) {
65  for (USI d = wellOptTime[i]; d < wellOptTime[i + 1]; d++) {
66  wells[w].optSet[d] = WellOpt(tmpOptParam[i].opt);
67  }
68  }
69  }
70 
71  // for output
72  useVTK = output_param.outVTKParam.useVTK;
73 }
74 
75 void AllWells::Setup(const Grid& myGrid, const Bulk& myBulk)
76 {
78  SetupWell(myGrid, myBulk);
79  SetPolyhedronWell(myGrid);
80  SetupMixture(myBulk);
81 }
82 
83 void AllWells::SetupWell(const Grid& myGrid, const Bulk& myBulk)
84 {
86 
87  for (USI w = 0; w < numWell; w++) {
88  wells[w].Setup(myGrid, myBulk, solvents);
89  }
90  SetupConnWell2Bulk(myBulk);
91 }
92 
93 void AllWells::SetupWellGroup(const Bulk& myBulk)
94 {
95  wellGroup.clear();
96  // Field Group, contain all wells
97  wellGroup.push_back(WellGroup("Field"));
98  for (USI w = 0; w < numWell; w++) {
99  wellGroup[0].wId.push_back(w);
100  if (wells[w].WellType() == INJ)
101  wellGroup[0].wIdINJ.push_back(w);
102  else
103  wellGroup[0].wIdPROD.push_back(w);
104  }
105 
106  // other subgroups
107  USI glen = 1;
108  USI g = 1;
109  for (USI w = 0; w < numWell; w++) {
110  for (g = 1; g < glen; g++) {
111  if (wells[w].group == wellGroup[g].name) {
112  // existing group
113  wellGroup[g].wId.push_back(w);
114  if (wells[w].WellType() == INJ)
115  wellGroup[g].wIdINJ.push_back(w);
116  else
117  wellGroup[g].wIdPROD.push_back(w);
118  break;
119  }
120  }
121  if (g == glen && wells[w].group != "Field") {
122  // new group
123  wellGroup.push_back(WellGroup(wells[w].group));
124  wellGroup[glen].wId.push_back(w);
125  if (wells[w].WellType() == INJ)
126  wellGroup[glen].wIdINJ.push_back(w);
127  else
128  wellGroup[glen].wIdPROD.push_back(w);
129  glen++;
130  }
131  }
132 
133  numGroup = wellGroup.size();
134  // relation between wellGroup should be completed if "node groups" exist
135 
136  // control of group should be update according to input file
137 
138  // for test
139  if (OCP_FALSE) {
140  wellGroup[0].reInj = OCP_TRUE;
141  wellGroup[0].saleRate = 1500;
142  wellGroup[0].reInjPhase = GAS;
143  wellGroup[0].prodGroup = 0;
144  }
145  wellGroup[0].reInjZi.resize(myBulk.GetComNum());
146  CalReInjFluid(myBulk);
147 }
148 
149 void AllWells::SetupMixture(const Bulk& myBulk)
150 {
151  OCP_FUNCNAME;
152 
153  flashCal = myBulk.GetMixture();
154 }
155 
156 void AllWells::SetupWellBulk(Bulk& myBulk) const
157 {
158  for (auto& w : wells) {
159  if (w.IsOpen()) {
160  for (auto& p : w.perf) {
161  myBulk.AddWellBulkId(p.Location());
162  }
163  }
164  }
165 }
166 
168 {
169  well2bulk.resize(numWell);
170  USI wId = 0;
171  for (auto& w : wells) {
172  for (auto& p : w.perf) well2bulk[wId].push_back(p.Location());
173  wId++;
174  }
175 }
176 
178 {
179  OCP_FUNCNAME;
180  wellChange = OCP_FALSE;
181  USI wId = 0;
182  for (USI w = 0; w < numWell; w++) {
183  wells[w].opt = wells[w].optSet[i];
184  if (wells[w].IsOpen()) {
185  wells[w].wOId = wId;
186  wId++;
187  }
188  if (i > 0 && wells[w].opt != wells[w].optSet[i - 1]) wellChange = OCP_TRUE;
189  }
190 }
191 
192 void AllWells::InitBHP(const Bulk& myBulk)
193 {
194  OCP_FUNCNAME;
195 
196  for (USI w = 0; w < numWell; w++) {
197  wells[w].InitBHP(myBulk);
198  }
199 }
200 
201 void AllWells::PrepareWell(const Bulk& myBulk)
202 {
203  OCP_FUNCNAME;
204 
205  for (USI w = 0; w < numWell; w++) {
206  if (wells[w].IsOpen()) {
207 
208  wells[w].CalTrans(myBulk);
209  wells[w].CaldG(myBulk);
210  wells[w].CheckOptMode(myBulk);
211  wells[w].CalFlux(myBulk, OCP_TRUE);
212  }
213  }
214 }
215 
216 void AllWells::CalTrans(const Bulk& myBulk)
217 {
218  OCP_FUNCNAME;
219 
220  for (USI w = 0; w < numWell; w++) {
221  if (wells[w].IsOpen()) {
222  wells[w].CalTrans(myBulk);
223  }
224  }
225 }
226 
227 void AllWells::CalFlux(const Bulk& myBulk)
228 {
229  OCP_FUNCNAME;
230 
231  for (USI w = 0; w < numWell; w++) {
232  if (wells[w].IsOpen()) {
233  wells[w].CalFlux(myBulk, OCP_FALSE);
234  }
235  }
236 }
237 
238 void AllWells::CaldG(const Bulk& myBulk)
239 {
240  OCP_FUNCNAME;
241 
242  for (USI w = 0; w < numWell; w++) {
243  if (wells[w].IsOpen()) {
244  wells[w].CaldG(myBulk);
245  }
246  }
247 }
248 
249 void AllWells::CalIPRT(const Bulk& myBulk, OCP_DBL dt)
250 {
251  OCP_FUNCNAME;
252 
253  FGIR = 0;
254  FWIR = 0;
255  FOPR = 0;
256  FGPR = 0;
257  FWPR = 0;
258  for (USI w = 0; w < numWell; w++) {
259  wells[w].WGIR = 0;
260  wells[w].WWIR = 0;
261  wells[w].WOPR = 0;
262  wells[w].WGPR = 0;
263  wells[w].WWPR = 0;
264 
265  if (wells[w].IsOpen()) {
266  if (wells[w].WellType() == PROD) {
267  wells[w].CalProdQj(myBulk, dt);
268  } else {
269  wells[w].CalInjQj(myBulk, dt);
270  }
271  }
272  FGIR += wells[w].WGIR;
273  FWIR += wells[w].WWIR;
274  FOPR += wells[w].WOPR;
275  FGPR += wells[w].WGPR;
276  FWPR += wells[w].WWPR;
277  }
278  FGIT += FGIR * dt;
279  FWIT += FWIR * dt;
280  FOPT += FOPR * dt;
281  FGPt += FGPR * dt;
282  FWPT += FWPR * dt;
283 }
284 
285 void AllWells::CalReInjFluid(const Bulk& myBulk)
286 {
287  for (auto& wG : wellGroup) {
288  if (wG.reInj) {
289  const USI nc = myBulk.GetComNum();
290  // const USI np = myBulk.GetPhaseNum();
291  fill(wG.reInjZi.begin(), wG.reInjZi.end(), 0.0);
292  for (auto& prod : wellGroup[wG.prodGroup].wIdPROD) {
293  Daxpy(nc, 1.0, &wells[prod].qi_lbmol[0], &wG.reInjZi[0]);
294  }
295  OCP_DBL qt = Dnorm1(nc, &wG.reInjZi[0]);
296  if (fabs(qt) < 1E-8) {
297  // Recalculate zi
298  fill(wG.reInjZi.begin(), wG.reInjZi.end(), 0.0);
299  for (auto& prod : wellGroup[wG.prodGroup].wIdPROD) {
300  wells[prod].CalReInjFluid(myBulk, wG.reInjZi);
301  }
302  qt = Dnorm1(nc, &wG.reInjZi[0]);
303  }
304  flashCal[0]->Flash(Psurf, Tsurf, &wG.reInjZi[0]);
305  Dcopy(nc, &wG.reInjZi[0], &flashCal[0]->xij[wG.reInjPhase * nc]);
306  wG.reInjXi = flashCal[0]->xi[wG.reInjPhase];
307  wG.reInjFactor = wG.reInjXi * flashCal[0]->vj[wG.reInjPhase] / qt;
308  // assign to every open injection well in wG
309  for (auto& w : wG.wIdINJ) {
310  if (wells[w].IsOpen()) {
311  wells[w].opt.reInj = OCP_TRUE;
312  wells[w].opt.connWell = wG.wIdPROD;
313  wells[w].opt.reInjPhase = wG.reInjPhase;
314  wells[w].opt.injZi = wG.reInjZi;
315  wells[w].opt.factorINJ =
316  wG.reInjXi * 1000; // Blackoil Model prohibited
317  wells[w].opt.reInjFactor = wG.reInjFactor;
318  wells[w].opt.maxRate =
319  -wG.saleRate * wells[w].opt.factorINJ; // Mscf -> ft3 -> lbmol
320  }
321  }
322  }
323  }
324 }
325 
326 void AllWells::ResetBHP()
327 {
328  for (auto& w : wells) {
329  if (w.IsOpen()) {
330  w.bhp = w.lbhp;
331  w.CorrectBHP();
332  }
333  }
334 }
335 
337 {
338  OCP_FUNCNAME;
339 
340  OCP_BOOL flagSwitch = OCP_FALSE;
341  OCP_BOOL flagCrossf = OCP_FALSE;
342 
343  for (USI w = 0; w < numWell; w++) {
344  if (wells[w].IsOpen()) {
345 
346  OCP_INT flag = wells[w].CheckP(myBulk);
347 
348  switch (flag) {
349  case WELL_NEGATIVE_PRESSURE:
350  return WELL_NEGATIVE_PRESSURE;
351 
352  case WELL_SWITCH_TO_BHPMODE:
353  flagSwitch = OCP_TRUE;
354  break;
355 
356  case WELL_CROSSFLOW:
357  flagCrossf = OCP_TRUE;
358  break;
359 
360  case WELL_SUCCESS:
361  default:
362  break;
363  }
364  }
365  }
366 
367  if (flagSwitch || flagCrossf) return WELL_SWITCH_TO_BHPMODE;
368 
369  return WELL_SUCCESS;
370 }
371 
372 // return the index of Specified well name
373 USI AllWells::GetIndex(const string& name) const
374 {
375  OCP_FUNCNAME;
376 
377  for (USI w = 0; w < numWell; w++) {
378  if (wells[w].name == name) {
379  return w;
380  }
381  }
382  OCP_ABORT("Well name not found!");
383 }
384 
386 {
387  USI numPerf = 0;
388  for (USI w = 0; w < numWell; w++) {
389  numPerf += wells[w].numPerf;
390  }
391  return numPerf;
392 }
393 
395 {
396  OCP_FUNCNAME;
397 
398  USI m = 0;
399  for (USI w = 0; w < numWell; w++) {
400  m = max(m, wells[w].numPerf);
401  }
402  return m;
403 }
404 
405 void AllWells::CalMaxBHPChange()
406 {
407  dPmax = 0;
408  for (USI w = 0; w < numWell; w++) {
409  if (wells[w].IsOpen()) {
410  dPmax = max(dPmax, fabs(wells[w].bhp - wells[w].lbhp));
411  }
412  }
413 }
414 
415 void AllWells::SetPolyhedronWell(const Grid& myGrid)
416 {
417  if (!useVTK) return;
418 
419  wellVal.resize(numWell);
420  polyhedronWell.resize(numWell);
421  for (USI w = 0; w < numWell; w++) {
422  wells[w].SetPolyhedronWell(myGrid, polyhedronWell[w]);
423  }
424 }
425 
426 void AllWells::SetWellVal() const
427 {
428  if (!useVTK) return;
429 
430  for (USI w = 0; w < numWell; w++) {
431  if (wells[w].opt.state) {
432  if (wells[w].opt.type == INJ) {
433  if (wells[w].opt.optMode == BHP_MODE)
434  wellVal[w] = wells[w].opt.maxBHP;
435  else
436  wellVal[w] = wells[w].opt.maxRate;
437  } else {
438  if (wells[w].opt.optMode == BHP_MODE)
439  wellVal[w] = wells[w].opt.minBHP;
440  else
441  wellVal[w] = wells[w].opt.maxRate;
442  }
443  } else {
444  wellVal[w] = 0;
445  }
446  }
447 }
448 
449 /*----------------------------------------------------------------------------*/
450 /* Brief Change History of This File */
451 /*----------------------------------------------------------------------------*/
452 /* Author Date Actions */
453 /*----------------------------------------------------------------------------*/
454 /* Shizhe Li Oct/01/2021 Create file */
455 /* Chensong Zhang Oct/15/2021 Format file */
456 /*----------------------------------------------------------------------------*/
AllWells class declaration.
void Daxpy(const int &n, const double &alpha, const double *x, double *y)
Constant times a vector plus a vector.
Definition: DenseMat.cpp:68
double Dnorm1(const int &N, double *x)
Computes the L1-norm of a vector.
Definition: DenseMat.cpp:49
void Dcopy(const int &N, double *dst, const double *src)
Calculate the minimal eigenvalue for symmetric matrix with mkl lapack.
Definition: DenseMat.cpp:36
unsigned int USI
Generic unsigned integer.
Definition: OCPConst.hpp:23
const USI GAS
Fluid type = gas.
Definition: OCPConst.hpp:92
double OCP_DBL
Double precision.
Definition: OCPConst.hpp:27
const USI PROD
Well type = producer.
Definition: OCPConst.hpp:123
int OCP_INT
Long integer.
Definition: OCPConst.hpp:26
const USI INJ
Well type = injector.
Definition: OCPConst.hpp:122
const USI BHP_MODE
Well option = fixed bottom-hole-pressure.
Definition: OCPConst.hpp:135
unsigned int OCP_BOOL
OCP_BOOL in OCP.
Definition: OCPConst.hpp:29
#define OCP_FUNCNAME
Print Function Name.
Definition: UtilError.hpp:73
#define OCP_ABORT(msg)
Abort if critical error happens.
Definition: UtilError.hpp:47
void InputParam(const ParamWell &paramWell, const ParamOutput &output_param)
Input param from ParamWell.
Definition: AllWells.cpp:18
void CalFlux(const Bulk &myBulk)
Calculate volume flow rate and moles flow rate of each perforation.
Definition: AllWells.cpp:227
vector< vector< OCP_USI > > well2bulk
connections between wells and bulks
Definition: AllWells.hpp:177
OCP_DBL Psurf
well reference pressure
Definition: AllWells.hpp:184
vector< Well > wells
well set.
Definition: AllWells.hpp:174
void CalTrans(const Bulk &myBulk)
Calculate Transmissibility of Wells.
Definition: AllWells.cpp:216
vector< SolventINJ > solvents
Sets of Solvent.
Definition: AllWells.hpp:180
USI GetMaxWellPerNum() const
Calculate maximum num of perforations of all Wells.
Definition: AllWells.cpp:394
OCP_DBL dPmax
Maximum BHP change.
Definition: AllWells.hpp:181
void SetupWell(const Grid &myGrid, const Bulk &myBulk)
complete the information of well according to Grid and Bulk.
Definition: AllWells.cpp:83
OCP_INT CheckP(const Bulk &myBulk)
Check if unreasonable well pressure or perforation pressure occurs.
Definition: AllWells.cpp:336
OCP_DBL FWIR
water injection rate in field.
Definition: AllWells.hpp:237
void SetupConnWell2Bulk(const Bulk &myBulk)
Setup the static connection between well and bulks.
Definition: AllWells.cpp:167
OCP_DBL FGIT
gas total injection in field.
Definition: AllWells.hpp:236
OCP_DBL FOPR
oil production rate in field.
Definition: AllWells.hpp:239
OCP_DBL FGPt
gas total production in field.
Definition: AllWells.hpp:242
void CaldG(const Bulk &myBulk)
Calculate dG.
Definition: AllWells.cpp:238
OCP_DBL FWPR
water production rate in field.
Definition: AllWells.hpp:243
vector< WellGroup > wellGroup
wellGroup set
Definition: AllWells.hpp:176
OCP_BOOL wellChange
if wells change, then OCP_TRUE
Definition: AllWells.hpp:179
void ApplyControl(const USI &i)
Apply the operation mode at the ith critical time.
Definition: AllWells.cpp:177
OCP_DBL FGIR
gas injection rate in field.
Definition: AllWells.hpp:235
void SetupMixture(const Bulk &myBulk)
get the mixture from bulk -— useless now
Definition: AllWells.cpp:149
OCP_DBL Tsurf
well reference temperature
Definition: AllWells.hpp:185
OCP_DBL FGPR
gas production rate in field.
Definition: AllWells.hpp:241
USI GetWellPerfNum() const
Return the num of perforations of all wells.
Definition: AllWells.cpp:385
void CalIPRT(const Bulk &myBulk, OCP_DBL dt)
Calculate Injection rate, total Injection, Production rate, total Production.
Definition: AllWells.cpp:249
void SetupWellBulk(Bulk &myBulk) const
Setup bulks which are penetrated by wells at current stage.
Definition: AllWells.cpp:156
OCP_DBL FWIT
water total injection in field.
Definition: AllWells.hpp:238
void InitBHP(const Bulk &myBulk)
Set the initial well pressure.
Definition: AllWells.cpp:192
OCP_DBL FOPT
oil total production in field.
Definition: AllWells.hpp:240
void SetupWellGroup(const Bulk &myBulk)
Setup information of wellGroup.
Definition: AllWells.cpp:93
USI numGroup
num of groups
Definition: AllWells.hpp:175
USI GetIndex(const string &name) const
Return the index of specified well.
Definition: AllWells.cpp:373
void Setup(const Grid &myGrid, const Bulk &myBulk)
Setup wells.
Definition: AllWells.cpp:75
void PrepareWell(const Bulk &myBulk)
Calculate well properties at the beginning of each time step.
Definition: AllWells.cpp:201
OCP_DBL FWPT
water total production in field.
Definition: AllWells.hpp:244
vector< Mixture * > flashCal
Useless now.
Definition: AllWells.hpp:183
USI numWell
num of wells.
Definition: AllWells.hpp:173
void CalReInjFluid(const Bulk &myBulk)
Calculate Reinjection fluid.
Definition: AllWells.cpp:285
Physical information of each active reservoir bulk.
Definition: Bulk.hpp:104
const vector< Mixture * > & GetMixture() const
Return flash.
Definition: Bulk.hpp:184
USI GetComNum() const
Return the number of components.
Definition: Bulk.hpp:150
void AddWellBulkId(const OCP_USI &n)
push back an element for wellBulkId
Definition: Bulk.hpp:504
Definition: Grid.hpp:89
OutputVTKParam outVTKParam
See OutputVTKParam.
OCP_DBL Psurf
Pressure in surface condition.
Definition: ParamWell.hpp:105
vector< Solvent > solSet
Sets of Solvent.
Definition: ParamWell.hpp:104
vector< OCP_DBL > criticalTime
Records the critical time given by users.
Definition: ParamWell.hpp:103
OCP_DBL Tsurf
Temperature in surface condition.
Definition: ParamWell.hpp:106
vector< WellParam > well
Contains all the information of wells.
Definition: ParamWell.hpp:102