tRenamed cell storativity to cell specific storativity - sphere - GPU-based 3D … | |
git clone git://src.adamsgaard.dk/sphere | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit 9f99cdfce0698a251618671dbb964b98bfe813f4 | |
parent 2852470952efcc1bb736355aa292487cfab8871b | |
Author: Anders Damsgaard <[email protected]> | |
Date: Mon, 24 Jun 2013 15:51:24 +0200 | |
Renamed cell storativity to cell specific storativity | |
Diffstat: | |
M src/darcy.cpp | 395 +++++++++++++++++++++++++----… | |
1 file changed, 328 insertions(+), 67 deletions(-) | |
--- | |
diff --git a/src/darcy.cpp b/src/darcy.cpp | |
t@@ -13,13 +13,15 @@ | |
// Initialize memory | |
void DEM::initDarcyMem() | |
{ | |
- unsigned int ncells = d_nx*d_ny*d_nz; | |
+ //unsigned int ncells = d_nx*d_ny*d_nz; | |
+ unsigned int ncells = (d_nx+2)*(d_ny+2)*(d_nz+2); | |
d_H = new Float[ncells]; // hydraulic pressure matrix | |
d_H_new = new Float[ncells]; // hydraulic pressure matrix | |
d_V = new Float3[ncells]; // Cell hydraulic velocity | |
d_dH = new Float3[ncells]; // Cell spatial gradient in hydraulic pressures | |
d_K = new Float[ncells]; // hydraulic conductivity matrix | |
- d_S = new Float[ncells]; // hydraulic storativity matrix | |
+ d_T = new Float3[ncells]; // hydraulic transmissivity matrix | |
+ d_Ss = new Float[ncells]; // hydraulic storativity matrix | |
d_W = new Float[ncells]; // hydraulic recharge | |
d_n = new Float[ncells]; // cell porosity | |
} | |
t@@ -32,7 +34,8 @@ void DEM::freeDarcyMem() | |
free(d_V); | |
free(d_dH); | |
free(d_K); | |
- free(d_S); | |
+ free(d_T); | |
+ free(d_Ss); | |
free(d_W); | |
free(d_n); | |
} | |
t@@ -43,52 +46,135 @@ unsigned int DEM::idx( | |
const unsigned int y, | |
const unsigned int z) | |
{ | |
- return x + d_nx*y + d_nx*d_ny*z; | |
+ //return x + d_nx*y + d_nx*d_ny*z; | |
+ return (x+1) + (d_nx+2)*(y+1) + (d_nx+2)*(d_ny+2)*(z+1); // with ghost nod… | |
} | |
// Set initial values | |
void DEM::initDarcyVals() | |
{ | |
- unsigned int ix, iy, iz; | |
+ // Hydraulic permeability [m^2] | |
+ const Float k = 1.0e-10; | |
+ | |
+ // Density of the fluid [kg/m^3] | |
+ const Float rho = 3600.0; | |
+ | |
+ unsigned int ix, iy, iz, cellidx; | |
for (ix=0; ix<d_nx; ++ix) { | |
for (iy=0; iy<d_ny; ++iy) { | |
for (iz=0; iz<d_nz; ++iz) { | |
+ cellidx = idx(ix,iy,iz); | |
+ | |
// Initial hydraulic head [m] | |
- //d_H[idx(ix,iy,iz)] = 1.0; | |
+ //d_H[cellidx] = 1.0; | |
// read from input binary | |
- // Hydraulic conductivity [m/s] | |
- d_K[idx(ix,iy,iz)] = 1.5; | |
+ // Hydraulic permeability [m^2] | |
+ d_K[cellidx] = k*rho*-params.g[2]/params.nu; | |
// Hydraulic storativity [-] | |
- d_S[idx(ix,iy,iz)] = 7.5e-3; | |
+ d_Ss[cellidx] = 8.0e-3; | |
// Hydraulic recharge [Pa/s] | |
- d_W[idx(ix,iy,iz)] = 0.0; | |
+ d_W[cellidx] = 0.0; | |
} | |
} | |
} | |
} | |
-Float DEM::minVal3dArr(Float* arr) | |
+ | |
+// Copy values from cell with index 'read' to cell with index 'write' | |
+void DEM::copyDarcyVals(unsigned int read, unsigned int write) | |
+{ | |
+ d_H[write] = d_H[read]; | |
+ d_H_new[write] = d_H_new[read]; | |
+ d_V[write] = MAKE_FLOAT3(d_V[read].x, d_V[read].y, d_V[read].z); | |
+ d_dH[write] = MAKE_FLOAT3(d_dH[read].x, d_dH[read].y, d_dH[read].z); | |
+ d_K[write] = d_K[read]; | |
+ d_T[write] = MAKE_FLOAT3(d_T[read].x, d_T[read].y, d_T[read].z); | |
+ d_Ss[write] = d_Ss[read]; | |
+ d_W[write] = d_W[read]; | |
+ d_n[write] = d_n[read]; | |
+} | |
+ | |
+// Update ghost nodes from their parent cell values | |
+// The edge (diagonal) cells are not written since they are not read | |
+void DEM::setDarcyGhostNodes() | |
{ | |
- Float minval = 1e16; // a large val | |
- Float val; | |
unsigned int ix, iy, iz; | |
+ | |
+ // The x-normal plane | |
+ for (iy=0; iy<d_ny; ++iy) { | |
+ for (iz=0; iz<d_nz; ++iz) { | |
+ | |
+ // Ghost nodes at x=-1 | |
+ copyDarcyVals( | |
+ idx(d_nx-1,iy,iz), // Read from this cell | |
+ idx(-1,iy,iz)); // Copy to this cell | |
+ | |
+ // Ghost nodes at x=d_nx | |
+ copyDarcyVals( | |
+ idx(0,iy,iz), | |
+ idx(d_nx,iy,iz)); | |
+ } | |
+ } | |
+ | |
+ // The y-normal plane | |
+ for (ix=0; ix<d_nx; ++ix) { | |
+ for (iz=0; iz<d_nz; ++iz) { | |
+ | |
+ // Ghost nodes at y=-1 | |
+ copyDarcyVals( | |
+ idx(ix,d_ny-1,iz), | |
+ idx(ix,-1,iz)); | |
+ | |
+ // Ghost nodes at y=d_ny | |
+ copyDarcyVals( | |
+ idx(ix,0,iz), | |
+ idx(ix,d_ny,iz)); | |
+ } | |
+ } | |
+ | |
+ // The z-normal plane | |
+ for (ix=0; ix<d_nx; ++ix) { | |
+ for (iy=0; iy<d_ny; ++iy) { | |
+ | |
+ // Ghost nodes at z=-1 | |
+ copyDarcyVals( | |
+ idx(ix,iy,d_nz-1), | |
+ idx(ix,iy,-1)); | |
+ | |
+ // Ghost nodes at z=d_nz | |
+ copyDarcyVals( | |
+ idx(ix,iy,0), | |
+ idx(ix,iy,d_nz)); | |
+ } | |
+ } | |
+} | |
+ | |
+// Find cell transmissivities from hydraulic conductivities and cell dimensions | |
+void DEM::findDarcyTransmissivities() | |
+{ | |
+ unsigned int ix, iy, iz, cellidx; | |
+ Float K; | |
for (ix=0; ix<d_nx; ++ix) { | |
for (iy=0; iy<d_ny; ++iy) { | |
for (iz=0; iz<d_nz; ++iz) { | |
- val = arr[idx(ix,iy,iz)]; | |
- if (minval > val) | |
- minval = val; | |
+ | |
+ cellidx = idx(ix,iy,iz); | |
+ K = d_K[cellidx]; | |
+ | |
+ // Hydraulic transmissivity [m2/s] | |
+ Float3 T = {K*d_dx, K*d_dy, K*d_dz}; | |
+ d_T[cellidx] = T; | |
} | |
} | |
} | |
} | |
- | |
// Set the gradient to 0.0 in all dimensions at the boundaries | |
+// Unused | |
void DEM::setDarcyBCNeumannZero() | |
{ | |
Float3 z3 = MAKE_FLOAT3(0.0, 0.0, 0.0); | |
t@@ -136,31 +222,75 @@ void DEM::findDarcyGradients() | |
Float H; | |
unsigned int ix, iy, iz, cellidx; | |
- for (ix=1; ix<d_nx-1; ++ix) { | |
+ // Without ghost-nodes | |
+ /*for (ix=1; ix<d_nx-1; ++ix) { | |
for (iy=1; iy<d_ny-1; ++iy) { | |
+ for (iz=1; iz<d_nz-1; ++iz) {*/ | |
+ | |
+ // With ghost-nodes | |
+ for (ix=0; ix<d_nx; ++ix) { | |
+ for (iy=0; iy<d_ny; ++iy) { | |
for (iz=1; iz<d_nz-1; ++iz) { | |
cellidx = idx(ix,iy,iz); | |
H = d_H[cellidx]; // cell hydraulic pressure | |
- // Second order central difference | |
+ // Second order central differences | |
+ // Periodic x boundaries (with ghost nodes) | |
d_dH[cellidx].x | |
= (d_H[idx(ix+1,iy,iz)] - 2.0*H + d_H[idx(ix-1,iy,iz)])/dx2; | |
- | |
+ | |
+ // Periodic y boundaries (with ghost nodes) | |
d_dH[cellidx].y | |
= (d_H[idx(ix,iy+1,iz)] - 2.0*H + d_H[idx(ix,iy-1,iz)])/dy2; | |
+ // Normal z boundaries | |
d_dH[cellidx].z | |
= (d_H[idx(ix,iy,iz+1)] - 2.0*H + d_H[idx(ix,iy,iz-1)])/dz2; | |
+ | |
+ /* | |
+ // Periodic x boundaries | |
+ if (ix == 0) { | |
+ d_dH[cellidx].x = (d_H[idx(ix+1,iy,iz)] | |
+ - 2.0*H + d_H[idx(d_nx-1,iy,iz)])/dx2; | |
+ } else if (ix == d_nx-1) { | |
+ d_dH[cellidx].x = (d_H[idx(0,iy,iz)] | |
+ - 2.0*H + d_H[idx(ix-1,iy,iz)])/dx2; | |
+ } else { | |
+ d_dH[cellidx].x = (d_H[idx(ix+1,iy,iz)] | |
+ - 2.0*H + d_H[idx(ix-1,iy,iz)])/dx2; | |
+ } | |
+ | |
+ // Periodic y boundaries | |
+ if (iy == 0) { | |
+ d_dH[cellidx].y = (d_H[idx(ix,iy+1,iz)] | |
+ - 2.0*H + d_H[idx(ix,d_ny-1,iz)])/dy2; | |
+ } else if (iy == d_ny-1) { | |
+ d_dH[cellidx].y = (d_H[idx(ix,0,iz)] | |
+ - 2.0*H + d_H[idx(ix,iy-1,iz)])/dy2; | |
+ } else { | |
+ d_dH[cellidx].y = (d_H[idx(ix,iy+1,iz)] | |
+ - 2.0*H + d_H[idx(ix,iy-1,iz)])/dy2; | |
+ }*/ | |
+ | |
} | |
} | |
} | |
} | |
+// Arithmetic mean of two numbers | |
+Float amean(Float a, Float b) { | |
+ return (a+b)*0.5; | |
+} | |
+ | |
+// Harmonic mean of two numbers | |
+Float hmean(Float a, Float b) { | |
+ return (2.0*a*b)/(a+b); | |
+} | |
// Perform an explicit step. | |
-// Boundary conditions are fixed gradient values (Neumann) | |
+// Boundary conditions are fixed values (Dirichlet) | |
void DEM::explDarcyStep() | |
{ | |
// Cell dims squared | |
t@@ -168,62 +298,120 @@ void DEM::explDarcyStep() | |
const Float dy2 = d_dy*d_dy; | |
const Float dz2 = d_dz*d_dz; | |
- // Find cell gradients | |
- findDarcyGradients(); | |
- setDarcyBCNeumannZero(); | |
+ //setDarcyBCNeumannZero(); | |
+ | |
+ // Update ghost node values from their parent cell values | |
+ setDarcyGhostNodes(); | |
// Explicit 3D finite difference scheme | |
- // new = old + gradient*timestep | |
+ // new = old + production*timestep + gradient*timestep | |
unsigned int ix, iy, iz, cellidx; | |
- Float K, H, d; | |
- Float T, Tx, Ty, Tz, S; | |
- Float dt = time.dt; | |
- /*for (ix=0; ix<d_nx; ++ix) { | |
+ Float K, H, deltaH; | |
+ Float Tx, Ty, Tz, S; | |
+ //Float Tx_n, Tx_p, Ty_n, Ty_p, Tz_n, Tz_p; | |
+ Float gradx_n, gradx_p, grady_n, grady_p, gradz_n, gradz_p; | |
+ for (ix=0; ix<d_nx; ++ix) { | |
for (iy=0; iy<d_ny; ++iy) { | |
- for (iz=0; iz<d_nz; ++iz) {*/ | |
- for (ix=1; ix<d_nx-1; ++ix) { | |
- for (iy=1; iy<d_ny-1; ++iy) { | |
- for (iz=1; iz<d_nz-1; ++iz) { | |
+ for (iz=0; iz<d_nz; ++iz) { | |
+ // Cell linear index | |
cellidx = idx(ix,iy,iz); | |
- K = d_K[cellidx]; // cell hydraulic conductivity | |
- //H = d_H[cellidx]; // cell hydraulic pressure | |
- | |
- // Cell size | |
- d = d_dx; | |
- | |
- // Cell hydraulic transmissivity (as long as nx=ny=nz) | |
- T = K*d; | |
- | |
- // Transmissivity (arithmetic mean, harmonic mean may be bette… | |
- Tx = (d_K[idx(ix-1,iy,iz)]*d + T + d_K[idx(ix+1,iy,iz)])/3.0; | |
- Ty = (d_K[idx(ix,iy-1,iz)]*d + T + d_K[idx(ix,iy+1,iz)])/3.0; | |
- Tz = (d_K[idx(ix,iy,iz-1)]*d + T + d_K[idx(ix,iy,iz+1)])/3.0; | |
- | |
- // Cell hydraulic storativity (as long as nx=ny=nz) | |
- S = d_S[cellidx]*d; // not d^3 ? | |
- | |
- d_H_new[cellidx] = d_H[cellidx] + | |
- dt/S * | |
- (Tx*d_dH[cellidx].x | |
- + Ty*d_dH[cellidx].y | |
- + Tz*d_dH[cellidx].z | |
- + d_W[cellidx]); // Cell recharge | |
- | |
- //d_H[cellidx] | |
- //+= d_W[cellidx]*dt // cell recharge | |
- //+ K*dt * // diffusivity term | |
- //(d_dH[cellidx].x + d_dH[cellidx].y + d_dH[cellidx].z); | |
+ // If x,y,z boundaries are fixed values: | |
+ // Enforce Dirichlet BC | |
+ /*if (ix == 0 || iy == 0 || iz == 0 || | |
+ ix == d_nx-1 || iy == d_ny-1 || iz == d_nz-1) { | |
+ d_H_new[cellidx] = d_H[cellidx];*/ | |
+ // If z boundaries are periodic: | |
+ if (iz == 0 || iz == d_nz-1) { | |
+ d_H_new[cellidx] = d_H[cellidx]; | |
+ } else { | |
+ | |
+ // Cell hydraulic conductivity | |
+ K = d_K[cellidx]; | |
+ | |
+ // Cell hydraulic transmissivities | |
+ Tx = K*d_dx; | |
+ Ty = K*d_dy; | |
+ Tz = K*d_dz; | |
+ | |
+ // Cell hydraulic head | |
+ H = d_H[cellidx]; | |
+ | |
+ // Harmonic mean of transmissivity | |
+ // (in neg. and pos. direction along axis from cell) | |
+ // with periodic x and y boundaries | |
+ // without ghost nodes | |
+ /* | |
+ if (ix == 0) | |
+ gradx_n = hmean(Tx, d_T[idx(d_nx-1,iy,iz)].x) | |
+ * (d_H[idx(d_nx-1,iy,iz)] - H)/dx2; | |
+ else | |
+ gradx_n = hmean(Tx, d_T[idx(ix-1,iy,iz)].x) | |
+ * (d_H[idx(ix-1,iy,iz)] - H)/dx2; | |
+ | |
+ if (ix == d_nx-1) | |
+ gradx_p = hmean(Tx, d_T[idx(0,iy,iz)].x) | |
+ * (d_H[idx(0,iy,iz)] - H)/dx2; | |
+ else | |
+ gradx_p = hmean(Tx, d_T[idx(ix+1,iy,iz)].x) | |
+ * (d_H[idx(ix+1,iy,iz)] - H)/dx2; | |
+ | |
+ if (iy == 0) | |
+ grady_n = hmean(Ty, d_T[idx(ix,d_ny-1,iz)].y) | |
+ * (d_H[idx(ix,d_ny-1,iz)] - H)/dy2; | |
+ else | |
+ grady_n = hmean(Ty, d_T[idx(ix,iy-1,iz)].y) | |
+ * (d_H[idx(ix,iy-1,iz)] - H)/dy2; | |
+ | |
+ if (iy == d_ny-1) | |
+ grady_p = hmean(Ty, d_T[idx(ix,0,iz)].y) | |
+ * (d_H[idx(ix,0,iz)] - H)/dy2; | |
+ else | |
+ grady_p = hmean(Ty, d_T[idx(ix,iy+1,iz)].y) | |
+ * (d_H[idx(ix,iy+1,iz)] - H)/dy2; | |
+ */ | |
+ | |
+ gradx_n = hmean(Tx, d_T[idx(ix-1,iy,iz)].x) | |
+ * (d_H[idx(ix-1,iy,iz)] - H)/dx2; | |
+ gradx_p = hmean(Tx, d_T[idx(ix+1,iy,iz)].x) | |
+ * (d_H[idx(ix+1,iy,iz)] - H)/dx2; | |
+ | |
+ grady_n = hmean(Ty, d_T[idx(ix,iy-1,iz)].y) | |
+ * (d_H[idx(ix,iy-1,iz)] - H)/dy2; | |
+ grady_p = hmean(Ty, d_T[idx(ix,iy+1,iz)].y) | |
+ * (d_H[idx(ix,iy+1,iz)] - H)/dy2; | |
+ | |
+ gradz_n = hmean(Tz, d_T[idx(ix,iy,iz-1)].z) | |
+ * (d_H[idx(ix,iy,iz-1)] - H)/dz2; | |
+ gradz_p = hmean(Tz, d_T[idx(ix,iy,iz+1)].z) | |
+ * (d_H[idx(ix,iy,iz+1)] - H)/dz2; | |
+ | |
+ // Cell hydraulic storativity | |
+ S = d_Ss[cellidx]*d_dx*d_dy*d_dz; | |
+ | |
+ // Laplacian operator | |
+ deltaH = time.dt/S * | |
+ ( gradx_n + gradx_p | |
+ + grady_n + grady_p | |
+ + gradz_n + gradz_p | |
+ + d_W[cellidx] ); | |
+ | |
+ // Calculate new hydraulic pressure in cell | |
+ d_H_new[cellidx] = H + deltaH; | |
+ } | |
} | |
} | |
} | |
- // Swap d_H and d_H_new | |
- swapFloatArrays(d_H, d_H_new); | |
- | |
// Find macroscopic cell fluid velocities | |
findDarcyVelocities(); | |
+ | |
+ // Swap d_H and d_H_new | |
+ Float* tmp = d_H; | |
+ d_H = d_H_new; | |
+ d_H_new = tmp; | |
+ | |
} | |
// Print array values to file stream (stdout, stderr, other file) | |
t@@ -285,6 +473,9 @@ void DEM::findDarcyVelocities() | |
// Porosity [-]: n | |
+ // Find cell gradients | |
+ findDarcyGradients(); | |
+ | |
unsigned int ix, iy, iz, cellidx; | |
for (ix=0; ix<d_nx; ++ix) { | |
for (iy=0; iy<d_ny; ++iy) { | |
t@@ -323,7 +514,7 @@ Float3 DEM::cellMinBoundaryDarcy( | |
return x_min; | |
} | |
-// Return the lower corner coordinates of a cell | |
+// Return the upper corner coordinates of a cell | |
Float3 DEM::cellMaxBoundaryDarcy( | |
const unsigned int x, | |
const unsigned int y, | |
t@@ -395,7 +586,7 @@ std::vector<unsigned int> DEM::particlesInCell( | |
// Add fluid drag to the particles inside each cell | |
void DEM::fluidDragDarcy() | |
{ | |
- unsigned int ix, iy, iz, cellidx; | |
+ /*unsigned int ix, iy, iz, cellidx; | |
for (ix=0; ix<d_nx; ++ix) { | |
for (iy=0; iy<d_ny; ++iy) { | |
for (iz=0; iz<d_nz; ++iz) { | |
t@@ -403,6 +594,73 @@ void DEM::fluidDragDarcy() | |
} | |
} | |
+ }*/ | |
+} | |
+ | |
+// Get maximum value in 3d array with ghost nodes | |
+Float DEM::getTmax() | |
+{ | |
+ Float max = -1.0e13; // initialize with a small number | |
+ unsigned int ix,iy,iz; | |
+ Float3 val; | |
+ for (ix=0; ix<d_nx; ++ix) { | |
+ for (iy=0; iy<d_ny; ++iy) { | |
+ for (iz=0; iz<d_nz; ++iz) { | |
+ val = d_T[idx(ix,iy,iz)]; | |
+ if (val.x > max) | |
+ max = val.x; | |
+ if (val.y > max) | |
+ max = val.y; | |
+ if (val.z > max) | |
+ max = val.z; | |
+ } | |
+ } | |
+ } | |
+ return max; | |
+} | |
+// Get maximum value in 1d array with ghost nodes | |
+Float DEM::getSmin() | |
+{ | |
+ Float min = 1.0e13; // initialize with a small number | |
+ unsigned int ix,iy,iz; | |
+ Float val; | |
+ for (ix=0; ix<d_nx; ++ix) { | |
+ for (iy=0; iy<d_ny; ++iy) { | |
+ for (iz=0; iz<d_nz; ++iz) { | |
+ val = d_Ss[idx(ix,iy,iz)]; | |
+ if (val < min) | |
+ min = val; | |
+ } | |
+ } | |
+ } | |
+ return min; | |
+} | |
+ | |
+ | |
+// Check whether the time step length is sufficient for keeping the explicit | |
+// time stepping method stable | |
+void DEM::checkDarcyTimestep() | |
+{ | |
+ Float T_max = getTmax(); | |
+ Float S_min = getSsmin()*d_dx*d_dy*d_dz; | |
+ | |
+ // Use numerical criterion from Sonnenborg & Henriksen 2005 | |
+ Float value = T_max/S_min | |
+ * (time.dt/(d_dx*d_dx) + time.dt/(d_dy*d_dy) + time.dt/(d_dz*d_dz)); | |
+ | |
+ if (value > 0.5) { | |
+ std::cerr << "Error! The explicit darcy solution will be unstable.\n" | |
+ << "This happens due to a combination of the following:\n" | |
+ << " - The transmissivity T (i.e. hydraulic conductivity, K) is to… | |
+ << " (" << T_max << ")\n" | |
+ << " - The storativity S is too small" | |
+ << " (" << S_min << ")\n" | |
+ << " - The time step is too large" | |
+ << " (" << time.dt << ")\n" | |
+ << " - The cell dimensions are too small\n" | |
+ << " Reason: (" << value << " > 0.5)" | |
+ << std::endl; | |
+ exit(1); | |
} | |
} | |
t@@ -438,12 +696,15 @@ void DEM::initDarcy(const Float cellsizemultiplier) | |
initDarcyMem(); | |
initDarcyVals(); | |
+ findDarcyTransmissivities(); | |
+ | |
+ checkDarcyTimestep(); | |
} | |
// Print final heads and free memory | |
void DEM::endDarcy() | |
{ | |
- printDarcyArray(stdout, d_H, "d_H"); | |
+ //printDarcyArray(stdout, d_H, "d_H"); | |
//printDarcyArray(stdout, d_V, "d_V"); | |
//printDarcyArray(stdout, d_n, "d_n"); | |
freeDarcyMem(); |