GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
solvers_direct.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:      direkt linear equation system solvers
00009  *              part of the gpde library
00010  *               
00011  * COPYRIGHT:    (C) 2007 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 <math.h>
00020 #include <unistd.h>
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include "grass/gis.h"
00024 #include "grass/glocale.h"
00025 #include "grass/gmath.h"
00026 
00027 #define TINY 1.0e-20
00028 #define COMP_PIVOT 100
00029 
00043 int G_math_solver_gauss(double **A, double *x, double *b, int rows)
00044 {
00045     G_message(_("Starting direct gauss elimination solver"));
00046 
00047     G_math_gauss_elimination(A, b, rows);
00048     G_math_backward_solving(A, x, b, rows);
00049 
00050     return 1;
00051 }
00052 
00067 int G_math_solver_lu(double **A, double *x, double *b, int rows)
00068 {
00069     int i;
00070 
00071     double *c, *tmpv;
00072 
00073     G_message(_("Starting direct lu decomposition solver"));
00074 
00075     tmpv = G_alloc_vector(rows);
00076     c = G_alloc_vector(rows);
00077 
00078     G_math_lu_decomposition(A, b, rows);
00079 
00080 #pragma omp parallel
00081     {
00082 
00083 #pragma omp for  schedule (static) private(i)
00084         for (i = 0; i < rows; i++) {
00085             tmpv[i] = A[i][i];
00086             A[i][i] = 1;
00087         }
00088 
00089 #pragma omp single
00090         {
00091             G_math_forward_solving(A, b, b, rows);
00092         }
00093 
00094 #pragma omp for  schedule (static) private(i)
00095         for (i = 0; i < rows; i++) {
00096             A[i][i] = tmpv[i];
00097         }
00098 
00099 #pragma omp single
00100         {
00101             G_math_backward_solving(A, x, b, rows);
00102         }
00103     }
00104 
00105     G_free(c);
00106     G_free(tmpv);
00107 
00108 
00109     return 1;
00110 }
00111 
00126 int G_math_solver_cholesky(double **A, double *x, double *b, int bandwith,
00127                            int rows)
00128 {
00129 
00130     G_message(_("Starting cholesky decomposition solver"));
00131 
00132     if (G_math_cholesky_decomposition(A, rows, bandwith) != 1) {
00133         G_warning(_("Unable to solve the linear equation system"));
00134         return -2;
00135     }
00136 
00137     G_math_forward_solving(A, b, b, rows);
00138     G_math_backward_solving(A, x, b, rows);
00139 
00140     return 1;
00141 }
00142 
00155 void G_math_gauss_elimination(double **A, double *b, int rows)
00156 {
00157     int i, j, k;
00158 
00159     double tmpval = 0.0;
00160 
00161     /*compute the pivot -- commented out, because its meaningless
00162        to compute it only nth times. */
00163     /*G_math_pivot_create(A, b, rows, 0); */
00164 
00165     for (k = 0; k < rows - 1; k++) {
00166 #pragma omp parallel for schedule (static) private(i, j, tmpval) shared(k, A, b, rows)
00167         for (i = k + 1; i < rows; i++) {
00168             tmpval = A[i][k] / A[k][k];
00169             b[i] = b[i] - tmpval * b[k];
00170             for (j = k + 1; j < rows; j++) {
00171                 A[i][j] = A[i][j] - tmpval * A[k][j];
00172             }
00173         }
00174     }
00175 
00176     return;
00177 }
00178 
00192 void G_math_lu_decomposition(double **A, double *b, int rows)
00193 {
00194 
00195     int i, j, k;
00196 
00197     /*compute the pivot -- commented out, because its meaningless
00198        to compute it only nth times. */
00199     /*G_math_pivot_create(A, b, rows, 0); */
00200 
00201     for (k = 0; k < rows - 1; k++) {
00202 #pragma omp parallel for schedule (static) private(i, j) shared(k, A, rows)
00203         for (i = k + 1; i < rows; i++) {
00204             A[i][k] = A[i][k] / A[k][k];
00205             for (j = k + 1; j < rows; j++) {
00206                 A[i][j] = A[i][j] - A[i][k] * A[k][j];
00207             }
00208         }
00209     }
00210 
00211     return;
00212 }
00213 
00227 int G_math_cholesky_decomposition(double **A, int rows, int bandwith)
00228 {
00229 
00230     int i = 0, j = 0, k = 0;
00231 
00232     double sum_1 = 0.0;
00233 
00234     double sum_2 = 0.0;
00235 
00236     int colsize;
00237 
00238     if (bandwith <= 0)
00239         bandwith = rows;
00240 
00241     colsize = bandwith;
00242 
00243     for (k = 0; k < rows; k++) {
00244 #pragma omp parallel for schedule (static) private(i, j, sum_2) shared(A, k) reduction(+:sum_1)
00245         for (j = 0; j < k; j++) {
00246             sum_1 += A[k][j] * A[k][j];
00247         }
00248 
00249         if (0 > (A[k][k] - sum_1)) {
00250             G_warning("Matrix is not positive definite. break.");
00251             return -1;
00252         }
00253         A[k][k] = sqrt(A[k][k] - sum_1);
00254         sum_1 = 0.0;
00255 
00256         if ((k + bandwith) > rows) {
00257             colsize = rows;
00258         }
00259         else {
00260             colsize = k + bandwith;
00261         }
00262 
00263 #pragma omp parallel for schedule (static) private(i, j, sum_2) shared(A, k, sum_1, colsize)
00264 
00265         for (i = k + 1; i < colsize; i++) {
00266             sum_2 = 0.0;
00267             for (j = 0; j < k; j++) {
00268                 sum_2 += A[i][j] * A[k][j];
00269             }
00270             A[i][k] = (A[i][k] - sum_2) / A[k][k];
00271         }
00272 
00273     }
00274     /*we need to copy the lower triangle matrix to the upper trianle */
00275 #pragma omp parallel for schedule (static) private(i, k) shared(A, rows)
00276     for (k = 0; k < rows; k++) {
00277         for (i = k + 1; i < rows; i++) {
00278             A[k][i] = A[i][k];
00279         }
00280     }
00281 
00282 
00283     return 1;
00284 }
00285 
00296 void G_math_backward_solving(double **A, double *x, double *b, int rows)
00297 {
00298     int i, j;
00299 
00300     for (i = rows - 1; i >= 0; i--) {
00301         for (j = i + 1; j < rows; j++) {
00302             b[i] = b[i] - A[i][j] * x[j];
00303         }
00304         x[i] = (b[i]) / A[i][i];
00305     }
00306 
00307     return;
00308 }
00309 
00320 void G_math_forward_solving(double **A, double *x, double *b, int rows)
00321 {
00322     int i, j;
00323 
00324     double tmpval = 0.0;
00325 
00326     for (i = 0; i < rows; i++) {
00327         tmpval = 0;
00328         for (j = 0; j < i; j++) {
00329             tmpval += A[i][j] * x[j];
00330         }
00331         x[i] = (b[i] - tmpval) / A[i][i];
00332     }
00333 
00334     return;
00335 }
00336 
00337 
00357 int G_math_pivot_create(double **A, double *b, int rows, int start)
00358 {
00359     int num = 0;                /*number of changed rows */
00360 
00361     int i, j, k;
00362 
00363     double max;
00364 
00365     int number = 0;
00366 
00367     double tmpval = 0.0, s = 0.0;
00368 
00369     double *link = NULL;
00370 
00371     link = G_alloc_vector(rows);
00372 
00373     G_debug(2, "G_math_pivot_create: swap rows if needed");
00374     for (i = start; i < rows; i++) {
00375         s = 0.0;
00376         for (k = i + 1; k < rows; k++) {
00377             s += fabs(A[i][k]);
00378         }
00379         max = fabs(A[i][i]) / s;
00380         number = i;
00381         for (j = i + 1; j < rows; j++) {
00382             s = 0.0;
00383             for (k = j; k < rows; k++) {
00384                 s += fabs(A[j][k]);
00385             }
00386             /*search for the pivot element */
00387             if (max < fabs(A[j][i]) / s) {
00388                 max = fabs(A[j][i] / s);
00389                 number = j;
00390             }
00391         }
00392         if (max == 0) {
00393             max = TINY;
00394             G_warning("Matrix is singular");
00395         }
00396         /*if an pivot element was found, swap the les entries */
00397         if (number != i) {
00398 
00399             G_debug(4, "swap row %i with row %i", i, number);
00400 
00401             if (b != NULL) {
00402                 tmpval = b[number];
00403                 b[number] = b[i];
00404                 b[i] = tmpval;
00405             }
00406             G_math_d_copy(A[number], link, rows);
00407             G_math_d_copy(A[i], A[number], rows);
00408             G_math_d_copy(link, A[i], rows);
00409             num++;
00410         }
00411     }
00412 
00413     G_free_vector(link);
00414 
00415     return num;
00416 }