OpenCAEPoro  0.2.0 Sep/22/2022
A simulator for multicomponent porous media flow
Grid.cpp
Go to the documentation of this file.
1 
12 #include "Grid.hpp"
13 
14 void Grid::InputParam(const ParamReservoir &rs_param)
15 {
16  nx = rs_param.dimens.nx;
17  ny = rs_param.dimens.ny;
18  nz = rs_param.dimens.nz;
19  numGrid = rs_param.numGrid;
20 
21  if (!rs_param.coord.empty())
22  {
23  // CornerPoint Grid
24  gridType = CORNER_GRID;
25 
26  coord = rs_param.coord;
27  zcorn = rs_param.zcorn;
28  }
29  else
30  {
31  // Orthogonal Grid
32  gridType = ORTHOGONAL_GRID;
33 
34  numConn = 3 * nx * ny * nz - nx * ny - ny * nz - nz * nx;
35  tops = rs_param.tops;
36  dx = rs_param.dx;
37  dy = rs_param.dy;
38  dz = rs_param.dz;
39  }
40 
41  ntg = rs_param.ntg;
42  poro = rs_param.poro;
43  kx = rs_param.permX;
44  ky = rs_param.permY;
45  kz = rs_param.permZ;
46  SwatInit = rs_param.Swat;
47 
48  SATNUM.resize(numGrid, 0);
49  if (rs_param.SATNUM.activity)
50  {
51  for (OCP_USI i = 0; i < numGrid; i++)
52  {
53  SATNUM[i] = round(rs_param.SATNUM.data[i]) - 1;
54  }
55  }
56  PVTNUM.resize(numGrid, 0);
57  if (rs_param.PVTNUM.activity)
58  {
59  for (OCP_USI i = 0; i < numGrid; i++)
60  {
61  PVTNUM[i] = round(rs_param.PVTNUM.data[i]) - 1;
62  }
63  }
64  ACTNUM.resize(numGrid, 1);
65  if (rs_param.ACTNUM.activity)
66  {
67  for (OCP_USI i = 0; i < numGrid; i++)
68  {
69  ACTNUM[i] = round(rs_param.ACTNUM.data[i]);
70  }
71  }
72 }
73 
75 {
77  switch (gridType)
78  {
79  case ORTHOGONAL_GRID:
81  break;
82  case CORNER_GRID:
84  break;
85  default:
86  OCP_ABORT("WRONG Grid Type!");
87  }
88 
89  // test
90  CalSomeInfo();
91 }
92 
94 {
95  // x -> y -> z
98  CalActiveGrid(1E-6, 1E-6);
99 }
100 
102 {
103 
104  gNeighbor.resize(numGrid);
105  // PreAllocate
106  for (OCP_USI n = 0; n < numGrid; n++)
107  {
108  gNeighbor[n].reserve(6);
109  }
110 
111  // Begin Id and End Id in Grid, bIdg < eIdg
112  OCP_USI bIdg, eIdg;
113  OCP_DBL area;
114  OCP_USI nxny = nx * ny;
115 
116  for (USI k = 0; k < nz; k++)
117  {
118  for (USI j = 0; j < ny; j++)
119  {
120  for (USI i = 0; i < nx; i++)
121  {
122 
123  bIdg = k * nxny + j * nx + i;
124  // right -- x-direction
125  if (i < nx - 1)
126  {
127  eIdg = bIdg + 1;
128  area = CalAkdOrthogonalGrid(bIdg, eIdg, 1);
129  gNeighbor[bIdg].push_back(GPair(eIdg, area));
130  gNeighbor[eIdg].push_back(GPair(bIdg, area));
131  }
132 
133  // front -- y-direction
134  if (j < ny - 1)
135  {
136  eIdg = bIdg + nx;
137  area = CalAkdOrthogonalGrid(bIdg, eIdg, 2);
138  gNeighbor[bIdg].push_back(GPair(eIdg, area));
139  gNeighbor[eIdg].push_back(GPair(bIdg, area));
140  }
141 
142  // down -- z-direction
143  if (k < nz - 1)
144  {
145  eIdg = bIdg + nxny;
146  area = CalAkdOrthogonalGrid(bIdg, eIdg, 3);
147  gNeighbor[bIdg].push_back(GPair(eIdg, area));
148  gNeighbor[eIdg].push_back(GPair(bIdg, area));
149  }
150  }
151  }
152  }
153 
154  OCP_FUNCNAME;
155 }
156 
158  const USI &direction)
159 {
160  OCP_DBL T1;
161  OCP_DBL T2;
162  switch (direction)
163  {
164  case 1:
165  // x-direction
166  T1 = kx[bId] * ntg[bId] * dy[bId] * dz[bId] / dx[bId];
167  T2 = kx[eId] * ntg[eId] * dy[eId] * dz[eId] / dx[eId];
168  return (2 / (1 / T1 + 1 / T2));
169  break;
170  case 2:
171  // y-direction
172  T1 = ky[bId] * ntg[bId] * dz[bId] * dx[bId] / dy[bId];
173  T2 = ky[eId] * ntg[eId] * dz[eId] * dx[eId] / dy[eId];
174  return (2 / (1 / T1 + 1 / T2));
175  break;
176  case 3:
177  // z-direction -- no ntg
178  T1 = kz[bId] * dx[bId] * dy[bId] / dz[bId];
179  T2 = kz[eId] * dx[eId] * dy[eId] / dz[eId];
180  return (2 / (1 / T1 + 1 / T2));
181  break;
182  default:
183  OCP_ABORT("Wrong Direction!");
184  }
185 }
186 
188 {
189  depth.resize(numGrid, 0);
190  OCP_USI nxny = nx * ny;
191  // 0th layer
192  for (USI j = 0; j < ny; j++)
193  {
194  for (USI i = 0; i < nx; i++)
195  {
196  OCP_USI id = j * nx + i;
197  depth[id] = tops[id] + dz[id] / 2;
198  }
199  }
200  // 1th - (nz-1)th layer
201  for (USI k = 1; k < nz; k++)
202  {
203  OCP_USI knxny = k * nxny;
204  for (USI j = 0; j < ny; j++)
205  {
206  for (USI i = 0; i < nx; i++)
207  {
208  OCP_USI id = knxny + j * nx + i;
209  depth[id] = depth[id - nxny] + dz[id - nxny] / 2 + dz[id] / 2;
210  }
211  }
212  }
213 
214  v.resize(numGrid);
215  for (OCP_USI i = 0; i < numGrid; i++)
216  v[i] = dx[i] * dy[i] * dz[i];
217 }
218 
220 {
221  COORD coordTmp;
222  coordTmp.Allocate(nx, ny, nz);
223  coordTmp.InputData(coord, zcorn);
224  // coordTmp.CalConn();
225  coordTmp.SetupCornerPoints();
226  SetupNeighborCornerGrid(coordTmp);
227  CalActiveGrid(1E-6, 1E-6);
228 }
229 
231 {
232 
233  dx = CoTmp.dx;
234  dy = CoTmp.dy;
235  dz = CoTmp.dz;
236  v = CoTmp.v;
237  depth = CoTmp.depth;
238 
239  gNeighbor.resize(numGrid);
240  // PreAllocate
241  for (OCP_USI n = 0; n < numGrid; n++)
242  {
243  gNeighbor[n].reserve(10);
244  }
245 
246  // test
247  // cout << "Grid : " << CoTmp.numConn << endl;
248 
249  OCP_USI bIdg, eIdg;
250  OCP_DBL area;
251  for (OCP_USI n = 0; n < CoTmp.numConn; n++)
252  {
253  const GeneralConnect &ConnTmp = CoTmp.connect[n];
254  bIdg = ConnTmp.begin;
255  eIdg = ConnTmp.end;
256  area = CalAkdCornerGrid(ConnTmp);
257  gNeighbor[bIdg].push_back(GPair(eIdg, area));
258  gNeighbor[eIdg].push_back(GPair(bIdg, area));
259 
260  // USI I, J, K;
261  // GetIJKGrid(I, J, K, bIdg);
262  // cout << "(" << setw(3) << I << "," << setw(3) << J << "," << setw(3) << K << ") ";
263  // cout << setw(6) << bIdg;
264  // cout << " ";
265  // GetIJKGrid(I, J, K, eIdg);
266  // cout << "(" << setw(3) << I << "," << setw(3) << J << "," << setw(3) << K << ") ";
267  // cout << setw(6) << eIdg;
268  // cout << setw(20) << fixed << setprecision(4) << area;
269 
270  // cout << endl;
271  }
272 }
273 
275 {
276  OCP_USI bId = conn.begin;
277  OCP_USI eId = conn.end;
278  OCP_DBL bArea = conn.Ad_dd_begin;
279  OCP_DBL eArea = conn.Ad_dd_end;
280  OCP_DBL T1, T2;
281 
282  switch (conn.directionType)
283  {
284  case 1:
285  T1 = ntg[bId] * kx[bId] * bArea;
286  T2 = ntg[eId] * kx[eId] * eArea;
287  return 1 / (1 / T1 + 1 / T2);
288  break;
289  case 2:
290  T1 = ntg[bId] * ky[bId] * bArea;
291  T2 = ntg[eId] * ky[eId] * eArea;
292  return 1 / (1 / T1 + 1 / T2);
293  break;
294  case 3:
295  T1 = kz[bId] * bArea;
296  T2 = kz[eId] * eArea;
297  return 1 / (1 / T1 + 1 / T2);
298  break;
299  default:
300  OCP_ABORT("Wrong Direction Type!");
301  }
302 }
303 
305 // Note: Inactive cells do NOT participate simumlation; other rules can be given.
306 void Grid::CalActiveGrid(const OCP_DBL &e1, const OCP_DBL &e2)
307 {
308  activeMap_B2G.reserve(numGrid);
309  activeMap_G2B.resize(numGrid);
310  OCP_USI count = 0;
311  for (OCP_USI n = 0; n < numGrid; n++)
312  {
313  if (ACTNUM[n] == 0 || poro[n] * ntg[n] < e1 || v[n] < e2)
314  {
315  activeMap_G2B[n] = GB_Pair(false, 0);
316  continue;
317  }
318  activeMap_B2G.push_back(n);
319  activeMap_G2B[n] = GB_Pair(true, count);
320  count++;
321  }
322  activeGridNum = count;
323  cout << (numGrid - activeGridNum) * 100.0 / numGrid << "% ("
324  << (numGrid - activeGridNum) << ") of grid cell is inactive" << endl;
325 }
326 
328 OCP_USI Grid::GetActIndex(const USI &i, const USI &j, const USI &k) const
329 {
330  OCP_USI id = k * nx * ny + j * nx + i;
331  if (id > numGrid)
332  {
333  OCP_ABORT("Id is out of Range!");
334  }
335  bool activity = activeMap_G2B[id].IsAct();
336  if (!activity)
337  {
338  OCP_ABORT("(" + to_string(i) + "," + to_string(j) + "," + to_string(k) +
339  ") is inactive");
340  }
341  id = activeMap_G2B[id].GetId();
342  return id;
343 }
344 
345 // temp
346 void Grid::GetIJKGrid(USI &i, USI &j, USI &k, const OCP_USI &n) const
347 {
348  // i,j,k begin from 1
349  // n must be the index of grids instead bulks
350  k = n / (nx * ny) + 1;
351  j = (n - (k - 1) * nx * ny) / nx + 1;
352  i = n - (k - 1) * nx * ny - (j - 1) * nx + 1;
353 }
354 
355 
356 void Grid::GetIJKBulk(USI& i, USI& j, USI& k, const OCP_USI& n) const
357 {
358  GetIJKGrid(i, j, k, activeMap_B2G[n]);
359 }
360 
361 
362 void Grid::CalSomeInfo() const
363 {
364  // test
365  OCP_DBL depthMax = 0;
366  OCP_USI ndepa = 0;
367  OCP_DBL depthMin = 1E8;
368  OCP_USI ndepi = 0;
369  OCP_DBL dxMax = 0;
370  OCP_USI nxa = 0;
371  OCP_DBL dxMin = 1E8;
372  OCP_USI nxi = 0;
373  OCP_DBL dyMax = 0;
374  OCP_USI nya = 0;
375  OCP_DBL dyMin = 1E8;
376  OCP_USI nyi = 0;
377  OCP_DBL dzMax = 0;
378  OCP_USI nza = 0;
379  OCP_DBL dzMin = 1E8;
380  OCP_USI nzi = 0;
381  for (OCP_USI n = 0; n < numGrid; n++)
382  {
383  // if (!activeMap_G2B[nn].IsAct())
384  // continue;
385  // OCP_USI n = activeMap_G2B[nn].GetId();
386  if (depthMax < depth[n])
387  {
388  depthMax = depth[n];
389  ndepa = n;
390  }
391  if (depthMin > depth[n])
392  {
393  depthMin = depth[n];
394  ndepi = n;
395  }
396  if (dxMax < dx[n])
397  {
398  dxMax = dx[n];
399  nxa = n;
400  }
401  if (dxMin > dx[n])
402  {
403  dxMin = dx[n];
404  nxi = n;
405  }
406  if (dyMax < dy[n])
407  {
408  dyMax = dy[n];
409  nya = n;
410  }
411  if (dyMin > dy[n])
412  {
413  dyMin = dy[n];
414  nyi = n;
415  }
416  if (dzMax < dz[n])
417  {
418  dzMax = dz[n];
419  nza = n;
420  }
421  if (dzMin > dz[n])
422  {
423  dzMin = dz[n];
424  nzi = n;
425  }
426  }
427 
428  cout << "---------------------" << endl
429  << "GRID" << endl
430  << "---------------------" << endl;
431  cout << " Depthmax = " << depthMax << endl
432  << " Depthmin = " << depthMin << endl
433  << " DXmax = " << dxMax << endl
434  << " DXmin = " << dxMin << endl
435  << " DYmax = " << dyMax << endl
436  << " DYmin = " << dyMin << endl
437  << " DZmax = " << dzMax << endl
438  << " DZmin = " << dzMin << endl;
439 }
440 
442 {
443  OCP_ASSERT((nx > 0 & ny > 0 & nz > 0), "Wrong Dimension!");
444  numDigutIJK = 1;
445  if (log10(nx) > numDigutIJK) numDigutIJK = ceil(log10(nx));
446  if (log10(ny) > numDigutIJK) numDigutIJK = ceil(log10(ny));
447  if (log10(nz) > numDigutIJK) numDigutIJK = ceil(log10(nz));
448 }
449 
450 /*----------------------------------------------------------------------------*/
451 /* Brief Change History of This File */
452 /*----------------------------------------------------------------------------*/
453 /* Author Date Actions */
454 /*----------------------------------------------------------------------------*/
455 /* Shizhe Li Oct/01/2021 Create file */
456 /* Chensong Zhang Oct/15/2021 Format file */
457 /* Chensong Zhang Jan/16/2022 Fix Doxygen */
458 /*----------------------------------------------------------------------------*/
Grid class declaration.
const USI CORNER_GRID
Grid type = corner-point.
Definition: OCPConst.hpp:66
unsigned int USI
Generic unsigned integer.
Definition: OCPConst.hpp:22
double OCP_DBL
Double precision.
Definition: OCPConst.hpp:26
const USI ORTHOGONAL_GRID
Grid type = orthogonal.
Definition: OCPConst.hpp:65
unsigned int OCP_USI
Long unsigned integer.
Definition: OCPConst.hpp:24
#define OCP_FUNCNAME
Print Function Name.
Definition: UtilError.hpp:73
#define OCP_ASSERT(cond, msg)
Assert condition and log user messages in DEBUG mode.
Definition: UtilError.hpp:58
#define OCP_ABORT(msg)
Abort if critical error happens.
Definition: UtilError.hpp:47
USI nx
Num of bulks along x-direction.
USI ny
Num of bulks along y-direction.
USI nz
Num of bulks along z-direction.
Active cell indicator and its index among active cells.
Definition: Grid.hpp:48
Effective area of intersection surfaces with neighboring cells.
Definition: Grid.hpp:32
void CalNumDigutIJK()
only used in Structural grid
Definition: Grid.cpp:441
OCP_USI GetActIndex(const USI &i, const USI &j, const USI &k) const
Return the index of active cell (i, j, k).
Definition: Grid.cpp:328
void SetupCornerGrid()
Setup a corner-point grid.
Definition: Grid.cpp:219
OCP_DBL CalAkdOrthogonalGrid(const OCP_USI &bId, const OCP_USI &eId, const USI &direction)
Calculate Akd for an orthogonal grid.
Definition: Grid.cpp:157
void GetIJKGrid(USI &i, USI &j, USI &k, const OCP_USI &n) const
Return the 3D coordinate for object grid with Grid index.
Definition: Grid.cpp:346
OCP_DBL CalAkdCornerGrid(const GeneralConnect &conn)
Calculate Akd for a corner-point grid.
Definition: Grid.cpp:274
void SetupNeighborCornerGrid(const COORD &CoTmp)
Setup the neighboring info for a corner-point grid.
Definition: Grid.cpp:230
void InputParam(const ParamReservoir &rs_param)
Input parameters from the internal param structure.
Definition: Grid.cpp:14
void Setup()
Setup the grid information and calculate the properties.
Definition: Grid.cpp:74
void SetupOrthogonalGrid()
Setup an orthogonal grid.
Definition: Grid.cpp:93
void CalActiveGrid(const OCP_DBL &e1, const OCP_DBL &e2)
Calculate the activeness of grid cells.
Definition: Grid.cpp:306
void CalDepthVOrthogonalGrid()
Calculate the depth and volume for an orthogonal grid.
Definition: Grid.cpp:187
void GetIJKBulk(USI &i, USI &j, USI &k, const OCP_USI &n) const
Return the 3D coordinate for object grid with bulk(active grids) index.
Definition: Grid.cpp:356
void SetupNeighborOrthogonalGrid()
Setup the neighboring info for an orthogonal grid.
Definition: Grid.cpp:101
vector< OCP_DBL > permY
Permeability along the y-direction for each grid.
vector< OCP_DBL > zcorn
TODO: Add Doxygen.
Type_A_r< OCP_DBL > SATNUM
Records the index of SAT region for each grid.
Type_A_r< OCP_DBL > ACTNUM
Records the index of Active region for each grid.
vector< OCP_DBL > poro
Porosity for each grid.
vector< OCP_DBL > dy
Size along the y - direction for each grid.
vector< OCP_DBL > permX
Permeability along the x - direction for each grid.
vector< OCP_DBL > permZ
Permeability along the z-direction for each grid.
vector< OCP_DBL > dx
Size along the x - direction for each grid.
vector< OCP_DBL > tops
Depth of the top surface of the uppermost grids.
Type_A_r< OCP_DBL > PVTNUM
Records the index of PVT region for each grid.
vector< OCP_DBL > ntg
Net to gross for each grid.
vector< OCP_DBL > coord
TODO: Add Doxygen.
Dimens dimens
Dimension of grid: the number of grids along x,y,z direction.
vector< OCP_DBL > dz
Size along the z - direction for each grid.
vector< OCP_DBL > Swat
Initial water saturation in each grid.
OCP_USI numGrid
Num of grids.
vector< T > data
Data of param.
bool activity
If false, this param is not given.