123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721 |
- /*****************************************************************************
- *
- * MODULE: Grass PDE Numerical Library
- * AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006
- * soerengebbert <at> gmx <dot> de
- *
- * PURPOSE: groundwater flow in porous media
- * part of the gpde library
- *
- * COPYRIGHT: (C) 2000 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #include <grass/N_gwflow.h>
- /* *************************************************************** */
- /* ***************** N_gwflow_data3d ***************************** */
- /* *************************************************************** */
- /*!
- * \brief Alllocate memory for the groundwater calculation data structure in 3 dimensions
- *
- * The groundwater calculation data structure will be allocated including
- * all appendant 3d and 2d arrays. The offset for the 3d arrays is one
- * to establish homogeneous Neumann boundary conditions at the calculation area border.
- * This data structure is used to create a linear equation system based on the computation of
- * groundwater flow in porous media with the finite volume method.
- *
- * \param cols int
- * \param rows int
- * \param depths int
- * \return N_gwflow_data3d *
- * */
- N_gwflow_data3d *N_alloc_gwflow_data3d(int cols, int rows, int depths,
- int river, int drain)
- {
- N_gwflow_data3d *data;
- data = (N_gwflow_data3d *) G_calloc(1, sizeof(N_gwflow_data3d));
- data->phead = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->phead_start = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->status = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->hc_x = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->hc_y = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->hc_z = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->q = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->s = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->nf = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->r = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- if (river) {
- data->river_head =
- N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->river_leak =
- N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->river_bed = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- }
- else {
- data->river_head = NULL;
- data->river_leak = NULL;
- data->river_bed = NULL;
- }
- if (drain) {
- data->drain_leak =
- N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- data->drain_bed = N_alloc_array_3d(cols, rows, depths, 1, DCELL_TYPE);
- }
- else {
- data->drain_leak = NULL;
- data->drain_bed = NULL;
- }
- return data;
- }
- /* *************************************************************** */
- /* ********************* N_free_gwflow_data3d ******************** */
- /* *************************************************************** */
- /*!
- * \brief Release the memory of the groundwater flow data structure in three dimensions
- *
- * \param data N_gwflow_data3d *
- * \return void *
- * */
- void N_free_gwflow_data3d(N_gwflow_data3d * data)
- {
- if (data->phead)
- N_free_array_3d(data->phead);
- if (data->phead_start)
- N_free_array_3d(data->phead_start);
- if (data->status)
- N_free_array_3d(data->status);
- if (data->hc_x)
- N_free_array_3d(data->hc_x);
- if (data->hc_y)
- N_free_array_3d(data->hc_y);
- if (data->hc_z)
- N_free_array_3d(data->hc_z);
- if (data->q)
- N_free_array_3d(data->q);
- if (data->s)
- N_free_array_3d(data->s);
- if (data->nf)
- N_free_array_3d(data->nf);
- if (data->r)
- N_free_array_2d(data->r);
- if (data->river_head)
- N_free_array_3d(data->river_head);
- if (data->river_leak)
- N_free_array_3d(data->river_leak);
- if (data->river_bed)
- N_free_array_3d(data->river_bed);
- if (data->drain_leak)
- N_free_array_3d(data->drain_leak);
- if (data->drain_bed)
- N_free_array_3d(data->drain_bed);
- G_free(data);
- data = NULL;
- return;
- }
- /* *************************************************************** */
- /* ******************** N_alloc_gwflow_data2d ******************** */
- /* *************************************************************** */
- /*!
- * \brief Alllocate memory for the groundwater calculation data structure in 2 dimensions
- *
- * The groundwater calculation data structure will be allocated including
- * all appendant 2d arrays. The offset for the 3d arrays is one
- * to establish homogeneous Neumann boundary conditions at the calculation area border.
- * This data structure is used to create a linear equation system based on the computation of
- * groundwater flow in porous media with the finite volume method.
- *
- * \param cols int
- * \param rows int
- * \return N_gwflow_data2d *
- * */
- N_gwflow_data2d *N_alloc_gwflow_data2d(int cols, int rows, int river,
- int drain)
- {
- N_gwflow_data2d *data;
- data = (N_gwflow_data2d *) G_calloc(1, sizeof(N_gwflow_data2d));
- data->phead = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->phead_start = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->status = N_alloc_array_2d(cols, rows, 1, CELL_TYPE);
- data->hc_x = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->hc_y = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->q = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->s = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->nf = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->r = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->top = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->bottom = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- if (river) {
- data->river_head = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->river_leak = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->river_bed = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- }
- else {
- data->river_head = NULL;
- data->river_leak = NULL;
- data->river_bed = NULL;
- }
- if (drain) {
- data->drain_leak = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- data->drain_bed = N_alloc_array_2d(cols, rows, 1, DCELL_TYPE);
- }
- else {
- data->drain_leak = NULL;
- data->drain_bed = NULL;
- }
- return data;
- }
- /* *************************************************************** */
- /* ****************** N_free_gwflow_data2d *********************** */
- /* *************************************************************** */
- /*!
- * \brief Release the memory of the groundwater flow data structure in two dimensions
- *
- * \param data N_gwflow_data2d *
- * \return void
- * */
- void N_free_gwflow_data2d(N_gwflow_data2d * data)
- {
- if (data->phead)
- N_free_array_2d(data->phead);
- if (data->phead_start)
- N_free_array_2d(data->phead_start);
- if (data->status)
- N_free_array_2d(data->status);
- if (data->hc_x)
- N_free_array_2d(data->hc_x);
- if (data->hc_y)
- N_free_array_2d(data->hc_y);
- if (data->q)
- N_free_array_2d(data->q);
- if (data->s)
- N_free_array_2d(data->s);
- if (data->nf)
- N_free_array_2d(data->nf);
- if (data->r)
- N_free_array_2d(data->r);
- if (data->top)
- N_free_array_2d(data->top);
- if (data->bottom)
- N_free_array_2d(data->bottom);
- if (data->river_head)
- N_free_array_2d(data->river_head);
- if (data->river_leak)
- N_free_array_2d(data->river_leak);
- if (data->river_bed)
- N_free_array_2d(data->river_bed);
- if (data->drain_leak)
- N_free_array_2d(data->drain_leak);
- if (data->drain_bed)
- N_free_array_2d(data->drain_bed);
- G_free(data);
- data = NULL;;
- return;
- }
- /* *************************************************************** */
- /* ***************** N_callback_gwflow_3d ************************ */
- /* *************************************************************** */
- /*!
- * \brief This callback function creates the mass balance of a 7 point star
- *
- * The mass balance is based on the common groundwater flow equation:
- *
- * \f[Ss \frac{\partial h}{\partial t} = \nabla {\bf K} \nabla h + q \f]
- *
- * This equation is discretizised with the finite volume method in three dimensions.
- *
- *
- * \param gwdata N_gwflow_data3d *
- * \param geom N_geom_data *
- * \param col int
- * \param row int
- * \param depth int
- * \return N_data_star *
- *
- * */
- N_data_star *N_callback_gwflow_3d(void *gwdata, N_geom_data * geom, int col,
- int row, int depth)
- {
- double hc_e = 0, hc_w = 0, hc_n = 0, hc_s = 0, hc_t = 0, hc_b = 0;
- double dx, dy, dz, Ax, Ay, Az;
- double hc_x, hc_y, hc_z;
- double hc_xw, hc_yn, hc_zt;
- double hc_xe, hc_ys, hc_zb;
- double hc_start;
- double Ss, r, nf, q;
- double C, W, E, N, S, T, B, V;
- N_data_star *mat_pos;
- N_gwflow_data3d *data;
- /*cast the void pointer to the right data structure */
- data = (N_gwflow_data3d *) gwdata;
- dx = geom->dx;
- dy = geom->dy;
- dz = geom->dz;
- Az = N_get_geom_data_area_of_cell(geom, row);
- Ay = geom->dx * geom->dz;
- Ax = geom->dz * geom->dy;
- /*read the data from the arrays */
- hc_start = N_get_array_3d_d_value(data->phead_start, col, row, depth);
- hc_x = N_get_array_3d_d_value(data->hc_x, col, row, depth);
- hc_y = N_get_array_3d_d_value(data->hc_y, col, row, depth);
- hc_z = N_get_array_3d_d_value(data->hc_z, col, row, depth);
- hc_xw = N_get_array_3d_d_value(data->hc_x, col - 1, row, depth);
- hc_xe = N_get_array_3d_d_value(data->hc_x, col + 1, row, depth);
- hc_yn = N_get_array_3d_d_value(data->hc_y, col, row - 1, depth);
- hc_ys = N_get_array_3d_d_value(data->hc_y, col, row + 1, depth);
- hc_zt = N_get_array_3d_d_value(data->hc_z, col, row, depth + 1);
- hc_zb = N_get_array_3d_d_value(data->hc_z, col, row, depth - 1);
- hc_w = N_calc_harmonic_mean(hc_xw, hc_x);
- hc_e = N_calc_harmonic_mean(hc_xe, hc_x);
- hc_n = N_calc_harmonic_mean(hc_yn, hc_y);
- hc_s = N_calc_harmonic_mean(hc_ys, hc_y);
- hc_t = N_calc_harmonic_mean(hc_zt, hc_z);
- hc_b = N_calc_harmonic_mean(hc_zb, hc_z);
- /*inner sources */
- q = N_get_array_3d_d_value(data->q, col, row, depth);
- /*storativity */
- Ss = N_get_array_3d_d_value(data->s, col, row, depth);
- /*porosity */
- nf = N_get_array_3d_d_value(data->nf, col, row, depth);
- /*mass balance center cell to western cell */
- W = -1 * Ax * hc_w / dx;
- /*mass balance center cell to eastern cell */
- E = -1 * Ax * hc_e / dx;
- /*mass balance center cell to northern cell */
- N = -1 * Ay * hc_n / dy;
- /*mass balance center cell to southern cell */
- S = -1 * Ay * hc_s / dy;
- /*mass balance center cell to top cell */
- T = -1 * Az * hc_t / dz;
- /*mass balance center cell to bottom cell */
- B = -1 * Az * hc_b / dz;
- /*storativity */
- Ss = Az * dz * Ss;
- /*the diagonal entry of the matrix */
- C = -1 * (W + E + N + S + T + B - Ss / data->dt * Az);
- /*the entry in the right side b of Ax = b */
- V = (q + hc_start * Ss / data->dt * Az);
- /*only the top cells will have recharge */
- if (depth == geom->depths - 2) {
- r = N_get_array_2d_d_value(data->r, col, row);
- V += r * Az;
- }
- G_debug(5, "N_callback_gwflow_3d: called [%i][%i][%i]", depth, col, row);
- /*create the 7 point star entries */
- mat_pos = N_create_7star(C, W, E, N, S, T, B, V);
- return mat_pos;
- }
- /* *************************************************************** */
- /* ****************** N_gwflow_3d_calc_water_budget ************** */
- /* *************************************************************** */
- /*!
- * \brief This function computes the water budget of the entire groundwater
- *
- * The water budget is calculated for each active and dirichlet cell from
- * its surrounding neighbours. This is based on the 7 star mass balance computation
- * of N_callback_gwflow_3d and the gradient of the water heights in the cells.
- * The sum of the water budget of each active/dirichlet cell must be near zero
- * due the effect of numerical inaccuracy of cpu's.
- *
- * \param gwdata N_gwflow_data3d *
- * \param geom N_geom_data *
- * \param budget N_array_3d
- * \return void
- *
- * */
- void
- N_gwflow_3d_calc_water_budget(N_gwflow_data3d * data, N_geom_data * geom, N_array_3d * budget)
- {
- int z, y, x, stat;
- double h, hc;
- double val;
- double sum;
- N_data_star *dstar;
- int rows = data->status->rows;
- int cols = data->status->cols;
- int depths = data->status->depths;
- sum = 0;
- for (z = 0; z < depths; z++) {
- for (y = 0; y < rows; y++) {
- G_percent(y, rows - 1, 10);
- for (x = 0; x < cols; x++) {
- stat = (int)N_get_array_3d_d_value(data->status, x, y, z);
- val = 0.0;
- if (stat != N_CELL_INACTIVE ) { /*all active/dirichlet cells */
- /* Compute the flow parameter */
- dstar = N_callback_gwflow_3d(data, geom, x, y, z);
- /* Compute the gradient in each direction pointing from the center */
- hc = N_get_array_3d_d_value(data->phead, x, y, z);
- if((int)N_get_array_3d_d_value(data->status, x + 1, y , z) != N_CELL_INACTIVE) {
- h = N_get_array_3d_d_value(data->phead, x + 1, y , z);
- val += dstar->E * (hc - h);
- }
- if((int)N_get_array_3d_d_value(data->status, x - 1, y , z) != N_CELL_INACTIVE) {
- h = N_get_array_3d_d_value(data->phead, x - 1, y , z);
- val += dstar->W * (hc - h);
- }
- if((int)N_get_array_3d_d_value(data->status, x , y + 1, z) != N_CELL_INACTIVE) {
- h = N_get_array_3d_d_value(data->phead, x , y + 1, z);
- val += dstar->S * (hc - h);
- }
- if((int)N_get_array_3d_d_value(data->status, x , y - 1, z) != N_CELL_INACTIVE) {
- h = N_get_array_3d_d_value(data->phead, x , y - 1, z);
- val += dstar->N * (hc - h);
- }
- if((int)N_get_array_3d_d_value(data->status, x , y , z + 1) != N_CELL_INACTIVE) {
- h = N_get_array_3d_d_value(data->phead, x , y , z + 1);
- val += dstar->T * (hc - h);
- }
- if((int)N_get_array_3d_d_value(data->status, x , y , z - 1) != N_CELL_INACTIVE) {
- h = N_get_array_3d_d_value(data->phead, x , y , z - 1);
- val += dstar->B * (hc - h);
- }
- sum += val;
- G_free(dstar);
- }
- else {
- Rast_set_null_value(&val, 1, DCELL_TYPE);
- }
- N_put_array_3d_d_value(budget, x, y, z, val);
- }
- }
- }
- if(fabs(sum) < 0.0000000001)
- G_message(_("The total sum of the water budget: %g\n"), sum);
- else
- G_warning(_("The total sum of the water budget is significantly larger then 0: %g\n"), sum);
- return;
- }
- /* *************************************************************** */
- /* ****************** N_callback_gwflow_2d *********************** */
- /* *************************************************************** */
- /*!
- * \brief This callback function creates the mass balance of a 5 point star
- *
- * The mass balance is based on the common groundwater flow equation:
- *
- * \f[Ss \frac{\partial h}{\partial t} = \nabla {\bf K} \nabla h + q \f]
- *
- * This equation is discretizised with the finite volume method in two dimensions.
- *
- * \param gwdata N_gwflow_data2d *
- * \param geom N_geom_data *
- * \param col int
- * \param row int
- * \return N_data_star *
- *
- * */
- N_data_star *N_callback_gwflow_2d(void *gwdata, N_geom_data * geom, int col,
- int row)
- {
- double T_e = 0, T_w = 0, T_n = 0, T_s = 0;
- double z_e = 0, z_w = 0, z_n = 0, z_s = 0;
- double dx, dy, Az;
- double hc_x, hc_y;
- double z, top;
- double hc_xw, hc_yn;
- double z_xw, z_yn;
- double hc_xe, hc_ys;
- double z_xe, z_ys;
- double hc, hc_start;
- double Ss, r, q;
- double C, W, E, N, S, V;
- N_gwflow_data2d *data;
- N_data_star *mat_pos;
- double river_vect = 0; /*entry in vector */
- double river_mat = 0; /*entry in matrix */
- double drain_vect = 0; /*entry in vector */
- double drain_mat = 0; /*entry in matrix */
- /*cast the void pointer to the right data structure */
- data = (N_gwflow_data2d *) gwdata;
- dx = geom->dx;
- dy = geom->dy;
- Az = N_get_geom_data_area_of_cell(geom, row);
- /*read the data from the arrays */
- hc_start = N_get_array_2d_d_value(data->phead_start, col, row);
- hc = N_get_array_2d_d_value(data->phead, col, row);
- top = N_get_array_2d_d_value(data->top, col, row);
- /* Inner sources */
- q = N_get_array_2d_d_value(data->q, col, row);
- /* storativity or porosity of current cell face [-]*/
- Ss = N_get_array_2d_d_value(data->s, col, row);
- /* recharge */
- r = N_get_array_2d_d_value(data->r, col, row) * Az;
- if (hc > top) { /*If the aquifer is confined */
- z = N_get_array_2d_d_value(data->top, col,
- row) -
- N_get_array_2d_d_value(data->bottom, col, row);
- z_xw =
- N_get_array_2d_d_value(data->top, col - 1,
- row) -
- N_get_array_2d_d_value(data->bottom, col - 1, row);
- z_xe =
- N_get_array_2d_d_value(data->top, col + 1,
- row) -
- N_get_array_2d_d_value(data->bottom, col + 1, row);
- z_yn =
- N_get_array_2d_d_value(data->top, col,
- row - 1) -
- N_get_array_2d_d_value(data->bottom, col, row - 1);
- z_ys =
- N_get_array_2d_d_value(data->top, col,
- row + 1) -
- N_get_array_2d_d_value(data->bottom, col, row + 1);
- }
- else { /* the aquifer is unconfined */
- /* If the aquifer is unconfied use an explicite scheme to solve
- * the nonlinear equation. We use the phead from the first iteration */
- z = N_get_array_2d_d_value(data->phead, col, row) -
- N_get_array_2d_d_value(data->bottom, col, row);
- z_xw = N_get_array_2d_d_value(data->phead, col - 1, row) -
- N_get_array_2d_d_value(data->bottom, col - 1, row);
- z_xe = N_get_array_2d_d_value(data->phead, col + 1, row) -
- N_get_array_2d_d_value(data->bottom, col + 1, row);
- z_yn = N_get_array_2d_d_value(data->phead, col, row - 1) -
- N_get_array_2d_d_value(data->bottom, col, row - 1);
- z_ys = N_get_array_2d_d_value(data->phead, col, row + 1) -
- N_get_array_2d_d_value(data->bottom, col, row + 1);
- }
- /*geometrical mean of cell height */
- if (z_w > 0 || z_w < 0 || z_w == 0)
- z_w = N_calc_arith_mean(z_xw, z);
- else
- z_w = z;
- if (z_e > 0 || z_e < 0 || z_e == 0)
- z_e = N_calc_arith_mean(z_xe, z);
- else
- z_e = z;
- if (z_n > 0 || z_n < 0 || z_n == 0)
- z_n = N_calc_arith_mean(z_yn, z);
- else
- z_n = z;
- if (z_s > 0 || z_s < 0 || z_s == 0)
- z_s = N_calc_arith_mean(z_ys, z);
- else
- z_s = z;
- /*get the surrounding permeabilities */
- hc_x = N_get_array_2d_d_value(data->hc_x, col, row);
- hc_y = N_get_array_2d_d_value(data->hc_y, col, row);
- hc_xw = N_get_array_2d_d_value(data->hc_x, col - 1, row);
- hc_xe = N_get_array_2d_d_value(data->hc_x, col + 1, row);
- hc_yn = N_get_array_2d_d_value(data->hc_y, col, row - 1);
- hc_ys = N_get_array_2d_d_value(data->hc_y, col, row + 1);
- /* calculate the transmissivities */
- T_w = N_calc_harmonic_mean(hc_xw, hc_x) * z_w;
- T_e = N_calc_harmonic_mean(hc_xe, hc_x) * z_e;
- T_n = N_calc_harmonic_mean(hc_yn, hc_y) * z_n;
- T_s = N_calc_harmonic_mean(hc_ys, hc_y) * z_s;
- /* Compute the river leakage, this is an explicit method
- * Influent and effluent flow is computed.
- */
- if (data->river_leak &&
- (N_get_array_2d_d_value(data->river_leak, col, row) != 0) &&
- N_get_array_2d_d_value(data->river_bed, col, row) <= top) {
- /* Groundwater surface is above the river bed*/
- if (hc > N_get_array_2d_d_value(data->river_bed, col, row)) {
- river_vect = N_get_array_2d_d_value(data->river_head, col, row) *
- N_get_array_2d_d_value(data->river_leak, col, row);
- river_mat = N_get_array_2d_d_value(data->river_leak, col, row);
- } /* Groundwater surface is below the river bed */
- else if (hc < N_get_array_2d_d_value(data->river_bed, col, row)) {
- river_vect = (N_get_array_2d_d_value(data->river_head, col, row) -
- N_get_array_2d_d_value(data->river_bed, col, row))
- * N_get_array_2d_d_value(data->river_leak, col, row);
- river_mat = 0;
- }
- }
- /* compute the drainage, this is an explicit method
- * Drainage is only enabled, if the drain bed is lower the groundwater surface
- */
- if (data->drain_leak &&
- (N_get_array_2d_d_value(data->drain_leak, col, row) != 0) &&
- N_get_array_2d_d_value(data->drain_bed, col, row) <= top) {
- if (hc > N_get_array_2d_d_value(data->drain_bed, col, row)) {
- drain_vect = N_get_array_2d_d_value(data->drain_bed, col, row) *
- N_get_array_2d_d_value(data->drain_leak, col, row);
- drain_mat = N_get_array_2d_d_value(data->drain_leak, col, row);
- }
- else if (hc <= N_get_array_2d_d_value(data->drain_bed, col, row)) {
- drain_vect = 0;
- drain_mat = 0;
- }
- }
- /*mass balance center cell to western cell */
- W = -1 * T_w * dy / dx;
- /*mass balance center cell to eastern cell */
- E = -1 * T_e * dy / dx;
- /*mass balance center cell to northern cell */
- N = -1 * T_n * dx / dy;
- /*mass balance center cell to southern cell */
- S = -1 * T_s * dx / dy;
- /*the diagonal entry of the matrix */
- C = -1 * (W + E + N + S - Az *Ss / data->dt - river_mat * Az -
- drain_mat * Az);
- /*the entry in the right side b of Ax = b */
- V = (q + hc_start * Az * Ss / data->dt) + r + river_vect * Az +
- drain_vect * Az;
- G_debug(5, "N_callback_gwflow_2d: called [%i][%i]", row, col);
- /*create the 5 point star entries */
- mat_pos = N_create_5star(C, W, E, N, S, V);
- return mat_pos;
- }
- /* *************************************************************** */
- /* ****************** N_gwflow_2d_calc_water_budget ************** */
- /* *************************************************************** */
- /*!
- * \brief This function computes the water budget of the entire groundwater
- *
- * The water budget is calculated for each active and dirichlet cell from
- * its surrounding neighbours. This is based on the 5 star mass balance computation
- * of N_callback_gwflow_2d and the gradient of the water heights in the cells.
- * The sum of the water budget of each active/dirichlet cell must be near zero
- * due the effect of numerical inaccuracy of cpu's.
- *
- * \param gwdata N_gwflow_data2d *
- * \param geom N_geom_data *
- * \param budget N_array_2d
- * \return void
- *
- * */
- void
- N_gwflow_2d_calc_water_budget(N_gwflow_data2d * data, N_geom_data * geom, N_array_2d * budget)
- {
- int y, x, stat;
- double h, hc;
- double val;
- double sum;
- N_data_star *dstar;
- int rows = data->status->rows;
- int cols = data->status->cols;
- sum = 0;
- for (y = 0; y < rows; y++) {
- G_percent(y, rows - 1, 10);
- for (x = 0; x < cols; x++) {
- stat = N_get_array_2d_c_value(data->status, x, y);
- val = 0.0;
- if (stat != N_CELL_INACTIVE ) { /*all active/dirichlet cells */
- /* Compute the flow parameter */
- dstar = N_callback_gwflow_2d(data, geom, x, y);
- /* Compute the gradient in each direction pointing from the center */
- hc = N_get_array_2d_d_value(data->phead, x, y);
- if((int)N_get_array_2d_d_value(data->status, x + 1, y ) != N_CELL_INACTIVE) {
- h = N_get_array_2d_d_value(data->phead, x + 1, y);
- val += dstar->E * (hc - h);
- }
- if((int)N_get_array_2d_d_value(data->status, x - 1, y ) != N_CELL_INACTIVE) {
- h = N_get_array_2d_d_value(data->phead, x - 1, y);
- val += dstar->W * (hc - h);
- }
- if((int)N_get_array_2d_d_value(data->status, x , y + 1) != N_CELL_INACTIVE) {
- h = N_get_array_2d_d_value(data->phead, x , y + 1);
- val += dstar->S * (hc - h);
- }
- if((int)N_get_array_2d_d_value(data->status, x , y - 1) != N_CELL_INACTIVE) {
- h = N_get_array_2d_d_value(data->phead, x , y - 1);
- val += dstar->N * (hc - h);
- }
- sum += val;
- G_free(dstar);
- }
- else {
- Rast_set_null_value(&val, 1, DCELL_TYPE);
- }
- N_put_array_2d_d_value(budget, x, y, val);
- }
- }
- if(fabs(sum) < 0.0000000001)
- G_message(_("The total sum of the water budget: %g\n"), sum);
- else
- G_warning(_("The total sum of the water budget is significantly larger then 0: %g\n"), sum);
- return;
- }
|