GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
N_gwflow.c
Go to the documentation of this file.
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 }