GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
N_gradient_calc.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:      gradient management functions 
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_pde.h>
00020 
00029 void N_calc_gradient_field_2d_stats(N_gradient_field_2d * field)
00030 {
00031     double minx, miny;
00032 
00033     double maxx, maxy;
00034 
00035     double sumx, sumy;
00036 
00037     int nonullx, nonully;
00038 
00039     G_debug(3,
00040             "N_calc_gradient_field_2d_stats: compute gradient field stats");
00041 
00042     N_calc_array_2d_stats(field->x_array, &minx, &maxx, &sumx, &nonullx, 0);
00043     N_calc_array_2d_stats(field->y_array, &miny, &maxy, &sumy, &nonully, 0);
00044 
00045     if (minx < miny)
00046         field->min = minx;
00047     else
00048         field->min = miny;
00049 
00050     if (maxx > maxy)
00051         field->max = maxx;
00052     else
00053         field->max = maxy;
00054 
00055     field->sum = sumx + sumy;
00056     field->nonull = nonullx + nonully;
00057     field->mean = field->sum / (double)field->nonull;
00058 
00059     return;
00060 }
00061 
00108 N_gradient_field_2d *N_compute_gradient_field_2d(N_array_2d * pot,
00109                                                  N_array_2d * weight_x,
00110                                                  N_array_2d * weight_y,
00111                                                  N_geom_data * geom,
00112                                                  N_gradient_field_2d *
00113                                                  gradfield)
00114 {
00115     int i, j;
00116 
00117     int rows, cols;
00118 
00119     double dx, dy, p1, p2, r1, r2, mean, grad, res;
00120 
00121     N_gradient_field_2d *field = gradfield;
00122 
00123 
00124     if (pot->cols != weight_x->cols || pot->cols != weight_y->cols)
00125         G_fatal_error
00126             ("N_compute_gradient_field_2d: the arrays are not of equal size");
00127 
00128     if (pot->rows != weight_x->rows || pot->rows != weight_y->rows)
00129         G_fatal_error
00130             ("N_compute_gradient_field_2d: the arrays are not of equal size");
00131 
00132     if (pot->cols != geom->cols || pot->rows != geom->rows)
00133         G_fatal_error
00134             ("N_compute_gradient_field_2d: array sizes and geometry data are different");
00135 
00136 
00137     G_debug(3, "N_compute_gradient_field_2d: compute gradient field");
00138 
00139     rows = pot->rows;
00140     cols = pot->cols;
00141     dx = geom->dx;
00142     dy = geom->dy;
00143 
00144     if (field == NULL) {
00145         field = N_alloc_gradient_field_2d(cols, rows);
00146     }
00147     else {
00148         if (field->cols != geom->cols || field->rows != geom->rows)
00149             G_fatal_error
00150                 ("N_compute_gradient_field_2d: gradient field sizes and geometry data are different");
00151     }
00152 
00153 
00154     for (j = 0; j < rows; j++)
00155         for (i = 0; i < cols - 1; i++) {
00156             grad = 0;
00157             mean = 0;
00158 
00159             /* Only compute if the arrays are not null */
00160             if (!N_is_array_2d_value_null(pot, i, j) &&
00161                 !N_is_array_2d_value_null(pot, i + 1, j)) {
00162                 p1 = N_get_array_2d_d_value(pot, i, j);
00163                 p2 = N_get_array_2d_d_value(pot, i + 1, j);
00164                 grad = (p1 - p2) / dx;  /* gradient */
00165             }
00166             if (!N_is_array_2d_value_null(weight_x, i, j) &&
00167                 !N_is_array_2d_value_null(weight_x, i + 1, j)) {
00168                 r1 = N_get_array_2d_d_value(weight_x, i, j);
00169                 r2 = N_get_array_2d_d_value(weight_x, i + 1, j);
00170                 mean = N_calc_harmonic_mean(r1, r2);    /*harmonical mean */
00171             }
00172 
00173             res = mean * grad;
00174 
00175             N_put_array_2d_d_value(field->x_array, i + 1, j, res);
00176 
00177         }
00178 
00179     for (j = 0; j < rows - 1; j++)
00180         for (i = 0; i < cols; i++) {
00181             grad = 0;
00182             mean = 0;
00183 
00184             /* Only compute if the arrays are not null */
00185             if (!N_is_array_2d_value_null(pot, i, j) &&
00186                 !N_is_array_2d_value_null(pot, i, j + 1)) {
00187                 p1 = N_get_array_2d_d_value(pot, i, j);
00188                 p2 = N_get_array_2d_d_value(pot, i, j + 1);
00189                 grad = (p1 - p2) / dy;  /* gradient */
00190             }
00191             if (!N_is_array_2d_value_null(weight_y, i, j) &&
00192                 !N_is_array_2d_value_null(weight_y, i, j + 1)) {
00193                 r1 = N_get_array_2d_d_value(weight_y, i, j);
00194                 r2 = N_get_array_2d_d_value(weight_y, i, j + 1);
00195                 mean = N_calc_harmonic_mean(r1, r2);    /*harmonical mean */
00196             }
00197 
00198             res = -1 * mean * grad;
00199 
00200             N_put_array_2d_d_value(field->y_array, i, j + 1, res);
00201 
00202         }
00203 
00204     /*Compute gradient field statistics */
00205     N_calc_gradient_field_2d_stats(field);
00206 
00207     return field;
00208 }
00209 
00248 void
00249 N_compute_gradient_field_components_2d(N_gradient_field_2d * field,
00250                                        N_array_2d * x_comp,
00251                                        N_array_2d * y_comp)
00252 {
00253     int i, j;
00254 
00255     int rows, cols;
00256 
00257     double vx, vy;
00258 
00259     N_array_2d *x = x_comp;
00260 
00261     N_array_2d *y = y_comp;
00262 
00263     N_gradient_2d grad;
00264 
00265 
00266     if (!x)
00267         G_fatal_error("N_compute_gradient_components_2d: x array is empty");
00268     if (!y)
00269         G_fatal_error("N_compute_gradient_components_2d: y array is empty");
00270 
00271     cols = field->x_array->cols;
00272     rows = field->x_array->rows;
00273 
00274     /*Check the array sizes */
00275     if (x->cols != cols || x->rows != rows)
00276         G_fatal_error
00277             ("N_compute_gradient_components_2d: the size of the x array doesn't fit the gradient field size");
00278     if (y->cols != cols || y->rows != rows)
00279         G_fatal_error
00280             ("N_compute_gradient_components_2d: the size of the y array doesn't fit the gradient field size");
00281 
00282     for (j = 0; j < rows; j++)
00283         for (i = 0; i < cols; i++) {
00284             N_get_gradient_2d(field, &grad, i, j);
00285 
00286             /* in case a gradient is zero, we expect a no flow boundary */
00287             if (grad.WC == 0.0 || grad.EC == 0.0)
00288                 vx = (grad.WC + grad.EC);
00289             else
00290                 vx = (grad.WC + grad.EC) / 2;
00291             if (grad.NC == 0.0 || grad.SC == 0.0)
00292                 vy = (grad.NC + grad.SC);
00293             else
00294                 vy = (grad.NC + grad.SC) / 2;
00295 
00296             N_put_array_2d_d_value(x, i, j, vx);
00297             N_put_array_2d_d_value(y, i, j, vy);
00298         }
00299 
00300     return;
00301 }
00302 
00311 void N_calc_gradient_field_3d_stats(N_gradient_field_3d * field)
00312 {
00313     double minx, miny, minz;
00314 
00315     double maxx, maxy, maxz;
00316 
00317     double sumx, sumy, sumz;
00318 
00319     int nonullx, nonully, nonullz;
00320 
00321     G_debug(3,
00322             "N_calc_gradient_field_3d_stats: compute gradient field stats");
00323 
00324     N_calc_array_3d_stats(field->x_array, &minx, &maxx, &sumx, &nonullx, 0);
00325     N_calc_array_3d_stats(field->y_array, &miny, &maxy, &sumy, &nonully, 0);
00326     N_calc_array_3d_stats(field->z_array, &minz, &maxz, &sumz, &nonullz, 0);
00327 
00328     if (minx <= minz && minx <= miny)
00329         field->min = minx;
00330     if (miny <= minz && miny <= minx)
00331         field->min = miny;
00332     if (minz <= minx && minz <= miny)
00333         field->min = minz;
00334 
00335     if (maxx >= maxz && maxx >= maxy)
00336         field->max = maxx;
00337     if (maxy >= maxz && maxy >= maxx)
00338         field->max = maxy;
00339     if (maxz >= maxx && maxz >= maxy)
00340         field->max = maxz;
00341 
00342     field->sum = sumx + sumy + sumz;
00343     field->nonull = nonullx + nonully + nonullz;
00344     field->mean = field->sum / (double)field->nonull;
00345 
00346     return;
00347 }
00348 
00349 
00400 N_gradient_field_3d *N_compute_gradient_field_3d(N_array_3d * pot,
00401                                                  N_array_3d * weight_x,
00402                                                  N_array_3d * weight_y,
00403                                                  N_array_3d * weight_z,
00404                                                  N_geom_data * geom,
00405                                                  N_gradient_field_3d *
00406                                                  gradfield)
00407 {
00408     int i, j, k;
00409 
00410     int cols, rows, depths;
00411 
00412     double dx, dy, dz, p1, p2, r1, r2, mean, grad, res;
00413 
00414     N_gradient_field_3d *field = gradfield;
00415 
00416 
00417     if (pot->cols != weight_x->cols || pot->cols != weight_y->cols ||
00418         pot->cols != weight_z->cols)
00419         G_fatal_error
00420             ("N_compute_gradient_field_3d: the arrays are not of equal size");
00421 
00422     if (pot->rows != weight_x->rows || pot->rows != weight_y->rows ||
00423         pot->rows != weight_z->rows)
00424         G_fatal_error
00425             ("N_compute_gradient_field_3d: the arrays are not of equal size");
00426 
00427     if (pot->depths != weight_x->depths || pot->depths != weight_y->depths ||
00428         pot->depths != weight_z->depths)
00429         G_fatal_error
00430             ("N_compute_gradient_field_3d: the arrays are not of equal size");
00431 
00432     if (pot->cols != geom->cols || pot->rows != geom->rows ||
00433         pot->depths != geom->depths)
00434         G_fatal_error
00435             ("N_compute_gradient_field_3d: array sizes and geometry data are different");
00436 
00437     G_debug(3, "N_compute_gradient_field_3d: compute gradient field");
00438 
00439     cols = geom->cols;
00440     rows = geom->rows;
00441     depths = geom->depths;
00442     dx = geom->dx;
00443     dy = geom->dy;
00444     dz = geom->dz;
00445 
00446     if (gradfield == NULL) {
00447         field = N_alloc_gradient_field_3d(cols, rows, depths);
00448     }
00449     else {
00450         if (field->cols != geom->cols || field->rows != geom->rows ||
00451             field->depths != geom->depths)
00452             G_fatal_error
00453                 ("N_compute_gradient_field_3d: gradient field sizes and geometry data are different");
00454     }
00455 
00456     for (k = 0; k < depths; k++)
00457         for (j = 0; j < rows; j++)
00458             for (i = 0; i < cols - 1; i++) {
00459                 grad = 0;
00460                 mean = 0;
00461 
00462                 /*Only compute if the arrays are not null */
00463                 if (!N_is_array_3d_value_null(pot, i, j, k) &&
00464                     !N_is_array_3d_value_null(pot, i + 1, j, k)) {
00465                     p1 = N_get_array_3d_d_value(pot, i, j, k);
00466                     p2 = N_get_array_3d_d_value(pot, i + 1, j, k);
00467                     grad = (p1 - p2) / dx;      /* gradient */
00468                 }
00469                 if (!N_is_array_3d_value_null(weight_x, i, j, k) &&
00470                     !N_is_array_3d_value_null(weight_x, i + 1, j, k)) {
00471                     r1 = N_get_array_3d_d_value(weight_x, i, j, k);
00472                     r2 = N_get_array_3d_d_value(weight_x, i + 1, j, k);
00473                     mean = N_calc_harmonic_mean(r1, r2);        /*harmonical mean */
00474                 }
00475 
00476                 res = mean * grad;
00477 
00478                 G_debug(6,
00479                         "N_compute_gradient_field_3d: X-direction insert value %6.5g at %i %i %i ",
00480                         res, k, j, i + 1);
00481 
00482                 N_put_array_3d_d_value(field->x_array, i + 1, j, k, res);
00483 
00484             }
00485 
00486     for (k = 0; k < depths; k++)
00487         for (j = 0; j < rows - 1; j++)
00488             for (i = 0; i < cols; i++) {
00489                 grad = 0;
00490                 mean = 0;
00491 
00492                 /* Only compute if the arrays are not null */
00493                 if (!N_is_array_3d_value_null(pot, i, j, k) &&
00494                     !N_is_array_3d_value_null(pot, i, j + 1, k)) {
00495                     p1 = N_get_array_3d_d_value(pot, i, j, k);
00496                     p2 = N_get_array_3d_d_value(pot, i, j + 1, k);
00497                     grad = (p1 - p2) / dy;      /* gradient */
00498                 }
00499                 if (!N_is_array_3d_value_null(weight_y, i, j, k) &&
00500                     !N_is_array_3d_value_null(weight_y, i, j + 1, k)) {
00501                     r1 = N_get_array_3d_d_value(weight_y, i, j, k);
00502                     r2 = N_get_array_3d_d_value(weight_y, i, j + 1, k);
00503                     mean = N_calc_harmonic_mean(r1, r2);        /*harmonical mean */
00504                 }
00505 
00506                 res = -1 * mean * grad; /*invert the direction, because we count from north to south,
00507                                          * but the gradient is defined in y direction */
00508 
00509                 G_debug(6,
00510                         "N_compute_gradient_field_3d: Y-direction insert value %6.5g at %i %i %i ",
00511                         res, k, j + 1, i);
00512 
00513                 N_put_array_3d_d_value(field->y_array, i, j + 1, k, res);
00514 
00515             }
00516 
00517     for (k = 0; k < depths - 1; k++)
00518         for (j = 0; j < rows; j++)
00519             for (i = 0; i < cols; i++) {
00520                 grad = 0;
00521                 mean = 0;
00522 
00523                 /* Only compute if the arrays are not null */
00524                 if (!N_is_array_3d_value_null(pot, i, j, k) &&
00525                     !N_is_array_3d_value_null(pot, i, j, k + 1)) {
00526                     p1 = N_get_array_3d_d_value(pot, i, j, k);
00527                     p2 = N_get_array_3d_d_value(pot, i, j, k + 1);
00528                     grad = (p1 - p2) / dz;      /* gradient */
00529                 }
00530                 if (!N_is_array_3d_value_null(weight_z, i, j, k) &&
00531                     !N_is_array_3d_value_null(weight_z, i, j, k + 1)) {
00532                     r1 = N_get_array_3d_d_value(weight_z, i, j, k);
00533                     r2 = N_get_array_3d_d_value(weight_z, i, j, k + 1);
00534                     mean = N_calc_harmonic_mean(r1, r2);        /*harmonical mean */
00535                 }
00536 
00537                 res = mean * grad;
00538 
00539                 G_debug(6,
00540                         "N_compute_gradient_field_3d: Z-direction insert value %6.5g at %i %i %i ",
00541                         res, k + 1, j, i);
00542 
00543                 N_put_array_3d_d_value(field->z_array, i, j, k + 1, res);
00544 
00545             }
00546 
00547     /*Compute gradient field statistics */
00548     N_calc_gradient_field_3d_stats(field);
00549 
00550     return field;
00551 }
00552 
00595 void
00596 N_compute_gradient_field_components_3d(N_gradient_field_3d * field,
00597                                        N_array_3d * x_comp,
00598                                        N_array_3d * y_comp,
00599                                        N_array_3d * z_comp)
00600 {
00601     int i, j, k;
00602 
00603     int rows, cols, depths;
00604 
00605     double vx, vy, vz;
00606 
00607     N_array_3d *x = x_comp;
00608 
00609     N_array_3d *y = y_comp;
00610 
00611     N_array_3d *z = z_comp;
00612 
00613     N_gradient_3d grad;
00614 
00615 
00616     if (!x)
00617         G_fatal_error("N_compute_gradient_components_3d: x array is empty");
00618     if (!y)
00619         G_fatal_error("N_compute_gradient_components_3d: y array is empty");
00620     if (!z)
00621         G_fatal_error("N_compute_gradient_components_3d: z array is empty");
00622 
00623     cols = field->x_array->cols;
00624     rows = field->x_array->rows;
00625     depths = field->x_array->depths;
00626 
00627     /*Check the array sizes */
00628     if (x->cols != cols || x->rows != rows || x->depths != depths)
00629         G_fatal_error
00630             ("N_compute_gradient_components_3d: the size of the x array doesn't fit the gradient field size");
00631     if (y->cols != cols || y->rows != rows || y->depths != depths)
00632         G_fatal_error
00633             ("N_compute_gradient_components_3d: the size of the y array doesn't fit the gradient field size");
00634     if (z->cols != cols || z->rows != rows || z->depths != depths)
00635         G_fatal_error
00636             ("N_compute_gradient_components_3d: the size of the z array doesn't fit the gradient field size");
00637 
00638     for (k = 0; k < depths; k++)
00639         for (j = 0; j < rows; j++)
00640             for (i = 0; i < cols; i++) {
00641                 N_get_gradient_3d(field, &grad, i, j, k);
00642                 /* in case a gradient is zero, we expect a no flow boundary */
00643                 if (grad.WC == 0.0 || grad.EC == 0.0)
00644                     vx = (grad.WC + grad.EC);
00645                 else
00646                     vx = (grad.WC + grad.EC) / 2;
00647                 if (grad.NC == 0.0 || grad.SC == 0.0)
00648                     vy = (grad.NC + grad.SC);
00649                 else
00650                     vy = (grad.NC + grad.SC) / 2;
00651                 if (grad.TC == 0.0 || grad.BC == 0.0)
00652                     vz = (grad.TC + grad.BC);
00653                 else
00654                     vz = (grad.TC + grad.BC) / 2;
00655 
00656                 N_put_array_3d_d_value(x, i, j, k, vx);
00657                 N_put_array_3d_d_value(y, i, j, k, vy);
00658                 N_put_array_3d_d_value(z, i, j, k, vz);
00659             }
00660 
00661 
00662     return;
00663 }