|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
00001 00002 /***************************************************************************** 00003 * 00004 * MODULE: Grass PDE Numerical Library 00005 * AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006 00006 * soerengebbert <at> gmx <dot> de 00007 * 00008 * PURPOSE: groundwater flow in porous media 00009 * part of the gpde library 00010 * 00011 * COPYRIGHT: (C) 2000 by the GRASS Development Team 00012 * 00013 * This program is free software under the GNU General Public 00014 * License (>=v2). Read the file COPYING that comes with GRASS 00015 * for details. 00016 * 00017 *****************************************************************************/ 00018 00019 #include "grass/N_gwflow.h" 00020 00021 /* *************************************************************** */ 00022 /* ***************** N_gwflow_data3d ***************************** */ 00023 /* *************************************************************** */ 00038 N_gwflow_data3d *N_alloc_gwflow_data3d(int cols, int rows, int depths, 00039 int river, int drain) 00040 { 00041 N_gwflow_data3d *data; 00042 00043 data = (N_gwflow_data3d *) G_calloc(1, sizeof(N_gwflow_data3d)); 00044 00045 data->phead = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00046 data->phead_start = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00047 data->status = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00048 data->hc_x = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00049 data->hc_y = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00050 data->hc_z = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00051 data->q = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00052 data->s = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00053 data->nf = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00054 data->r = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00055 00056 if (river) { 00057 data->river_head = 00058 N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00059 data->river_leak = 00060 N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00061 data->river_bed = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00062 } 00063 else { 00064 data->river_head = NULL; 00065 data->river_leak = NULL; 00066 data->river_bed = NULL; 00067 } 00068 00069 if (drain) { 00070 data->drain_leak = 00071 N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00072 data->drain_bed = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE); 00073 } 00074 else { 00075 data->drain_leak = NULL; 00076 data->drain_bed = NULL; 00077 } 00078 00079 return data; 00080 } 00081 00082 /* *************************************************************** */ 00083 /* ********************* N_free_gwflow_data3d ******************** */ 00084 /* *************************************************************** */ 00092 void N_free_gwflow_data3d(N_gwflow_data3d * data) 00093 { 00094 if (data->phead) 00095 N_free_array_3d(data->phead); 00096 if (data->phead_start) 00097 N_free_array_3d(data->phead_start); 00098 if (data->status) 00099 N_free_array_3d(data->status); 00100 if (data->hc_x) 00101 N_free_array_3d(data->hc_x); 00102 if (data->hc_y) 00103 N_free_array_3d(data->hc_y); 00104 if (data->hc_z) 00105 N_free_array_3d(data->hc_z); 00106 if (data->q) 00107 N_free_array_3d(data->q); 00108 if (data->s) 00109 N_free_array_3d(data->s); 00110 if (data->nf) 00111 N_free_array_3d(data->nf); 00112 if (data->r) 00113 N_free_array_2d(data->r); 00114 if (data->river_head) 00115 N_free_array_3d(data->river_head); 00116 if (data->river_leak) 00117 N_free_array_3d(data->river_leak); 00118 if (data->river_bed) 00119 N_free_array_3d(data->river_bed); 00120 if (data->drain_leak) 00121 N_free_array_3d(data->drain_leak); 00122 if (data->drain_bed) 00123 N_free_array_3d(data->drain_bed); 00124 00125 G_free(data); 00126 00127 data = NULL; 00128 00129 return; 00130 } 00131 00132 /* *************************************************************** */ 00133 /* ******************** N_alloc_gwflow_data2d ******************** */ 00134 /* *************************************************************** */ 00148 N_gwflow_data2d *N_alloc_gwflow_data2d(int cols, int rows, int river, 00149 int drain) 00150 { 00151 N_gwflow_data2d *data; 00152 00153 data = (N_gwflow_data2d *) G_calloc(1, sizeof(N_gwflow_data2d)); 00154 00155 data->phead = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00156 data->phead_start = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00157 data->status = N_alloc_array_2d(cols, rows, 1, CELL_TYPE); 00158 data->hc_x = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00159 data->hc_y = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00160 data->q = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00161 data->s = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00162 data->nf = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00163 data->r = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00164 data->top = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00165 data->bottom = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00166 00167 if (river) { 00168 data->river_head = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00169 data->river_leak = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00170 data->river_bed = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00171 } 00172 else { 00173 data->river_head = NULL; 00174 data->river_leak = NULL; 00175 data->river_bed = NULL; 00176 } 00177 00178 if (drain) { 00179 data->drain_leak = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00180 data->drain_bed = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE); 00181 } 00182 else { 00183 data->drain_leak = NULL; 00184 data->drain_bed = NULL; 00185 } 00186 00187 00188 return data; 00189 } 00190 00191 /* *************************************************************** */ 00192 /* ****************** N_free_gwflow_data2d *********************** */ 00193 /* *************************************************************** */ 00200 void N_free_gwflow_data2d(N_gwflow_data2d * data) 00201 { 00202 if (data->phead) 00203 N_free_array_2d(data->phead); 00204 if (data->phead_start) 00205 N_free_array_2d(data->phead_start); 00206 if (data->status) 00207 N_free_array_2d(data->status); 00208 if (data->hc_x) 00209 N_free_array_2d(data->hc_x); 00210 if (data->hc_y) 00211 N_free_array_2d(data->hc_y); 00212 if (data->q) 00213 N_free_array_2d(data->q); 00214 if (data->s) 00215 N_free_array_2d(data->s); 00216 if (data->nf) 00217 N_free_array_2d(data->nf); 00218 if (data->r) 00219 N_free_array_2d(data->r); 00220 if (data->top) 00221 N_free_array_2d(data->top); 00222 if (data->bottom) 00223 N_free_array_2d(data->bottom); 00224 if (data->river_head) 00225 N_free_array_2d(data->river_head); 00226 if (data->river_leak) 00227 N_free_array_2d(data->river_leak); 00228 if (data->river_bed) 00229 N_free_array_2d(data->river_bed); 00230 if (data->drain_leak) 00231 N_free_array_2d(data->drain_leak); 00232 if (data->drain_bed) 00233 N_free_array_2d(data->drain_bed); 00234 00235 G_free(data); 00236 00237 data = NULL;; 00238 00239 return; 00240 } 00241 00242 /* *************************************************************** */ 00243 /* ***************** N_callback_gwflow_3d ************************ */ 00244 /* *************************************************************** */ 00263 N_data_star *N_callback_gwflow_3d(void *gwdata, N_geom_data * geom, int col, 00264 int row, int depth) 00265 { 00266 double hc_e = 0, hc_w = 0, hc_n = 0, hc_s = 0, hc_t = 0, hc_b = 0; 00267 00268 double dx, dy, dz, Ax, Ay, Az; 00269 00270 double hc_x, hc_y, hc_z; 00271 00272 double hc_xw, hc_yn, hc_zt; 00273 00274 double hc_xe, hc_ys, hc_zb; 00275 00276 double hc_start; 00277 00278 double Ss, r, nf, q; 00279 00280 double C, W, E, N, S, T, B, V; 00281 00282 N_data_star *mat_pos; 00283 00284 N_gwflow_data3d *data; 00285 00286 /*cast the void pointer to the right data structure */ 00287 data = (N_gwflow_data3d *) gwdata; 00288 00289 dx = geom->dx; 00290 dy = geom->dy; 00291 dz = geom->dz; 00292 Az = N_get_geom_data_area_of_cell(geom, row); 00293 Ay = geom->dx * geom->dz; 00294 Ax = geom->dz * geom->dy; 00295 00296 /*read the data from the arrays */ 00297 hc_start = N_get_array_3d_d_value(data->phead_start, col, row, depth); 00298 00299 hc_x = N_get_array_3d_d_value(data->hc_x, col, row, depth); 00300 hc_y = N_get_array_3d_d_value(data->hc_y, col, row, depth); 00301 hc_z = N_get_array_3d_d_value(data->hc_z, col, row, depth); 00302 00303 hc_xw = N_get_array_3d_d_value(data->hc_x, col - 1, row, depth); 00304 hc_xe = N_get_array_3d_d_value(data->hc_x, col + 1, row, depth); 00305 hc_yn = N_get_array_3d_d_value(data->hc_y, col, row - 1, depth); 00306 hc_ys = N_get_array_3d_d_value(data->hc_y, col, row + 1, depth); 00307 hc_zt = N_get_array_3d_d_value(data->hc_z, col, row, depth + 1); 00308 hc_zb = N_get_array_3d_d_value(data->hc_z, col, row, depth - 1); 00309 00310 hc_w = N_calc_harmonic_mean(hc_xw, hc_x); 00311 hc_e = N_calc_harmonic_mean(hc_xe, hc_x); 00312 hc_n = N_calc_harmonic_mean(hc_yn, hc_y); 00313 hc_s = N_calc_harmonic_mean(hc_ys, hc_y); 00314 hc_t = N_calc_harmonic_mean(hc_zt, hc_z); 00315 hc_b = N_calc_harmonic_mean(hc_zb, hc_z); 00316 00317 /*inner sources */ 00318 q = N_get_array_3d_d_value(data->q, col, row, depth); 00319 /*specific yield */ 00320 Ss = N_get_array_3d_d_value(data->s, col, row, depth); 00321 /*porosity */ 00322 nf = N_get_array_3d_d_value(data->nf, col, row, depth); 00323 00324 /*mass balance center cell to western cell */ 00325 W = -1 * Ax * hc_w / dx; 00326 /*mass balance center cell to eastern cell */ 00327 E = -1 * Ax * hc_e / dx; 00328 /*mass balance center cell to northern cell */ 00329 N = -1 * Ay * hc_n / dy; 00330 /*mass balance center cell to southern cell */ 00331 S = -1 * Ay * hc_s / dy; 00332 /*mass balance center cell to top cell */ 00333 T = -1 * Az * hc_t / dz; 00334 /*mass balance center cell to bottom cell */ 00335 B = -1 * Az * hc_b / dz; 00336 00337 /*specific yield */ 00338 Ss = Az * dz * Ss; 00339 00340 /*the diagonal entry of the matrix */ 00341 C = -1 * (W + E + N + S + T + B - Ss / data->dt * Az); 00342 00343 /*the entry in the right side b of Ax = b */ 00344 V = (q + hc_start * Ss / data->dt * Az); 00345 00346 /*only the top cells will have recharge */ 00347 if (depth == geom->depths - 2) { 00348 r = N_get_array_2d_d_value(data->r, col, row); 00349 V += r * Az; 00350 } 00351 00352 G_debug(5, "N_callback_gwflow_3d: called [%i][%i][%i]", depth, col, row); 00353 00354 /*create the 7 point star entries */ 00355 mat_pos = N_create_7star(C, W, E, N, S, T, B, V); 00356 00357 return mat_pos; 00358 } 00359 00360 /* *************************************************************** */ 00361 /* ****************** N_callback_gwflow_2d *********************** */ 00362 /* *************************************************************** */ 00379 N_data_star *N_callback_gwflow_2d(void *gwdata, N_geom_data * geom, int col, 00380 int row) 00381 { 00382 double T_e = 0, T_w = 0, T_n = 0, T_s = 0; 00383 00384 double z_e = 0, z_w = 0, z_n = 0, z_s = 0; 00385 00386 double dx, dy, Az; 00387 00388 double hc_x, hc_y; 00389 00390 double z, top; 00391 00392 double hc_xw, hc_yn; 00393 00394 double z_xw, z_yn; 00395 00396 double hc_xe, hc_ys; 00397 00398 double z_xe, z_ys; 00399 00400 double hc, hc_start; 00401 00402 double Ss, r, nf, q; 00403 00404 double C, W, E, N, S, V; 00405 00406 N_gwflow_data2d *data; 00407 00408 N_data_star *mat_pos; 00409 00410 double river_vect = 0; /*entry in vector */ 00411 00412 double river_mat = 0; /*entry in matrix */ 00413 00414 double drain_vect = 0; /*entry in vector */ 00415 00416 double drain_mat = 0; /*entry in matrix */ 00417 00418 /*cast the void pointer to the right data structure */ 00419 data = (N_gwflow_data2d *) gwdata; 00420 00421 dx = geom->dx; 00422 dy = geom->dy; 00423 Az = N_get_geom_data_area_of_cell(geom, row); 00424 00425 /*read the data from the arrays */ 00426 hc_start = N_get_array_2d_d_value(data->phead_start, col, row); 00427 hc = N_get_array_2d_d_value(data->phead, col, row); 00428 top = N_get_array_2d_d_value(data->top, col, row); 00429 00430 00431 if (hc > top) { /*If the aquifer is confined */ 00432 z = N_get_array_2d_d_value(data->top, col, 00433 row) - 00434 N_get_array_2d_d_value(data->bottom, col, row); 00435 z_xw = 00436 N_get_array_2d_d_value(data->top, col - 1, 00437 row) - 00438 N_get_array_2d_d_value(data->bottom, col - 1, row); 00439 z_xe = 00440 N_get_array_2d_d_value(data->top, col + 1, 00441 row) - 00442 N_get_array_2d_d_value(data->bottom, col + 1, row); 00443 z_yn = 00444 N_get_array_2d_d_value(data->top, col, 00445 row - 1) - 00446 N_get_array_2d_d_value(data->bottom, col, row - 1); 00447 z_ys = 00448 N_get_array_2d_d_value(data->top, col, 00449 row + 1) - 00450 N_get_array_2d_d_value(data->bottom, col, row + 1); 00451 } 00452 else { /* the aquifer is unconfined */ 00453 00454 /* If the aquifer is unconfied use an explicite scheme to solve 00455 * the nonlinear equation. We use the phead from the first iteration */ 00456 z = N_get_array_2d_d_value(data->phead, col, row) - 00457 N_get_array_2d_d_value(data->bottom, col, row); 00458 z_xw = N_get_array_2d_d_value(data->phead, col - 1, row) - 00459 N_get_array_2d_d_value(data->bottom, col - 1, row); 00460 z_xe = N_get_array_2d_d_value(data->phead, col + 1, row) - 00461 N_get_array_2d_d_value(data->bottom, col + 1, row); 00462 z_yn = N_get_array_2d_d_value(data->phead, col, row - 1) - 00463 N_get_array_2d_d_value(data->bottom, col, row - 1); 00464 z_ys = N_get_array_2d_d_value(data->phead, col, row + 1) - 00465 N_get_array_2d_d_value(data->bottom, col, row + 1); 00466 } 00467 00468 /*geometrical mean of cell height */ 00469 if (z_w > 0 || z_w < 0 || z_w == 0) 00470 z_w = N_calc_arith_mean(z_xw, z); 00471 else 00472 z_w = z; 00473 if (z_e > 0 || z_e < 0 || z_e == 0) 00474 z_e = N_calc_arith_mean(z_xe, z); 00475 else 00476 z_e = z; 00477 if (z_n > 0 || z_n < 0 || z_n == 0) 00478 z_n = N_calc_arith_mean(z_yn, z); 00479 else 00480 z_n = z; 00481 if (z_s > 0 || z_s < 0 || z_s == 0) 00482 z_s = N_calc_arith_mean(z_ys, z); 00483 else 00484 z_s = z; 00485 00486 /* Inner sources */ 00487 q = N_get_array_2d_d_value(data->q, col, row); 00488 nf = N_get_array_2d_d_value(data->nf, col, row); 00489 00490 /* specific yield of current cell face */ 00491 Ss = N_get_array_2d_d_value(data->s, col, row) * Az; 00492 /* recharge */ 00493 r = N_get_array_2d_d_value(data->r, col, row) * Az; 00494 00495 /*get the surrounding permeabilities */ 00496 hc_x = N_get_array_2d_d_value(data->hc_x, col, row); 00497 hc_y = N_get_array_2d_d_value(data->hc_y, col, row); 00498 hc_xw = N_get_array_2d_d_value(data->hc_x, col - 1, row); 00499 hc_xe = N_get_array_2d_d_value(data->hc_x, col + 1, row); 00500 hc_yn = N_get_array_2d_d_value(data->hc_y, col, row - 1); 00501 hc_ys = N_get_array_2d_d_value(data->hc_y, col, row + 1); 00502 00503 /* calculate the transmissivities */ 00504 T_w = N_calc_harmonic_mean(hc_xw, hc_x) * z_w; 00505 T_e = N_calc_harmonic_mean(hc_xe, hc_x) * z_e; 00506 T_n = N_calc_harmonic_mean(hc_yn, hc_y) * z_n; 00507 T_s = N_calc_harmonic_mean(hc_ys, hc_y) * z_s; 00508 00509 /*compute the river leakage, this is an explicit method */ 00510 if (data->river_leak && 00511 (N_get_array_2d_d_value(data->river_leak, col, row) != 0)) { 00512 if (hc > N_get_array_2d_d_value(data->river_bed, col, row)) { 00513 river_vect = N_get_array_2d_d_value(data->river_head, col, row) * 00514 N_get_array_2d_d_value(data->river_leak, col, row); 00515 river_mat = N_get_array_2d_d_value(data->river_leak, col, row); 00516 } 00517 else if (hc < N_get_array_2d_d_value(data->river_bed, col, row)) { 00518 river_vect = (N_get_array_2d_d_value(data->river_head, col, row) - 00519 N_get_array_2d_d_value(data->river_bed, col, row)) 00520 * N_get_array_2d_d_value(data->river_leak, col, row); 00521 river_mat = 0; 00522 } 00523 } 00524 00525 /*compute the drainage, this is an explicit method */ 00526 if (data->drain_leak && 00527 (N_get_array_2d_d_value(data->drain_leak, col, row) != 0)) { 00528 if (hc > N_get_array_2d_d_value(data->drain_bed, col, row)) { 00529 drain_vect = N_get_array_2d_d_value(data->drain_bed, col, row) * 00530 N_get_array_2d_d_value(data->drain_leak, col, row); 00531 drain_mat = N_get_array_2d_d_value(data->drain_leak, col, row); 00532 } 00533 else if (hc <= N_get_array_2d_d_value(data->drain_bed, col, row)) { 00534 drain_vect = 0; 00535 drain_mat = 0; 00536 } 00537 } 00538 00539 /*mass balance center cell to western cell */ 00540 W = -1 * T_w * dy / dx; 00541 /*mass balance center cell to eastern cell */ 00542 E = -1 * T_e * dy / dx; 00543 /*mass balance center cell to northern cell */ 00544 N = -1 * T_n * dx / dy; 00545 /*mass balance center cell to southern cell */ 00546 S = -1 * T_s * dx / dy; 00547 00548 /*the diagonal entry of the matrix */ 00549 C = -1 * (W + E + N + S - Ss / data->dt - river_mat * Az - 00550 drain_mat * Az); 00551 00552 /*the entry in the right side b of Ax = b */ 00553 V = (q + hc_start * Ss / data->dt) + r + river_vect * Az + 00554 drain_vect * Az; 00555 00556 G_debug(5, "N_callback_gwflow_2d: called [%i][%i]", row, col); 00557 00558 /*create the 5 point star entries */ 00559 mat_pos = N_create_5star(C, W, E, N, S, V); 00560 00561 return mat_pos; 00562 }