PLUTO
math_lu_decomp.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Functions for LU decomposition and matrix inversion.
5  \author A. Mignone (mignone@ph.unito.it)
6  \date June 20, 2014
7 */
8 /* ///////////////////////////////////////////////////////////////////// */
9 #include "pluto.h"
10 
11 /* ********************************************************************* */
12 int LUDecompose (double **a, int n, int *indx, double *d)
13 /*!
14  * Perform LU decomposition. Adapted from Numerical Recipes.
15  * On output, replaces the matrix a[0..n-1][0..n-1] with its LU
16  * decomposition. indx[0..n-1] is a row vector that records the row
17  * permutation while d = 1 (-1) if the number of raw interchanges
18  * was even (odd).
19  * This function should be used in combination with LUBackSubst() to
20  * solve linear system of equations.
21  *
22  *********************************************************************** */
23 #define TINY 1.0e-20;
24 {
25  int i, imax, j, k;
26  double big, dum, sum, temp;
27  double *vv;
28 
29  vv = ARRAY_1D (n, double);
30  *d = 1.0;
31  for (i = 0; i < n; i++) {
32  big = 0.0;
33  for (j = 0; j < n; j++)
34  if ((temp = fabs (a[i][j])) > big)
35  big = temp;
36  if (big == 0.0) {
37 /* print1 ("! Singular matrix in routine LUDecompose - (i=%d, j=%d)",i,j); */
38  return (0);
39  }
40  vv[i] = 1.0 / big;
41  }
42  for (j = 0; j < n; j++) {
43  for (i = 0; i < j; i++) {
44  sum = a[i][j];
45  for (k = 0; k < i; k++)
46  sum -= a[i][k] * a[k][j];
47  a[i][j] = sum;
48  }
49  big = 0.0;
50  for (i = j; i < n; i++) {
51  sum = a[i][j];
52  for (k = 0; k < j; k++)
53  sum -= a[i][k] * a[k][j];
54  a[i][j] = sum;
55  if ((dum = vv[i] * fabs (sum)) >= big) {
56  big = dum;
57  imax = i;
58  }
59  }
60  if (j != imax) {
61  for (k = 0; k < n; k++) {
62  dum = a[imax][k];
63  a[imax][k] = a[j][k];
64  a[j][k] = dum;
65  }
66  *d = -(*d);
67  vv[imax] = vv[j];
68  }
69  indx[j] = imax;
70  if (a[j][j] == 0.0)
71  a[j][j] = TINY;
72  if (j != n - 1) {
73  dum = 1.0 / (a[j][j]);
74  for (i = j + 1; i < n; i++)
75  a[i][j] *= dum;
76  }
77  }
78  FreeArray1D(vv);
79  return (1); /* -- success -- */
80 }
81 #undef TINY
82 
83 /* ********************************************************************* */
84 void LUBackSubst (double **a, int n, int *indx, double b[])
85 /*!
86  * Solve a linear system of the type <tt>Ax = b</tt>, where \c A is
87  * a square matrix, \c x is the array of unknowns and \c b is given.
88  * This function must be called after LUDecompose()
89  * (adapted from Numerical Recipes).
90  * For the 1st time, use:
91  * \code
92  * LUDecompose (A,n,indx,&d);
93  * LUBackSubst (A,n,indx,b);
94  * \endcode
95  * The answer \c x will be given back in \c b and the original matrix \c A
96  * will be destroyed.
97  * For all subsequent time, to solve the same system wth a different
98  * right-hand side \c b, use
99  * \code
100  * LUBackSubst(A,n,indx,b);
101  * \endcode
102  * where \c A is the matrix that has been decomposed by LUDecompose() and
103  * \em not the original matrix \c A.
104  *
105  *********************************************************************** */
106 {
107  int i, ii = 0, ip, j;
108  double sum;
109 
110  for (i = 0; i < n; i++) {
111  ip = indx[i];
112  sum = b[ip];
113  b[ip] = b[i];
114  if (ii)
115  for (j = ii - 1; j <= i - 1; j++)
116  sum -= a[i][j] * b[j];
117  else if (sum)
118  ii = i + 1;
119  b[i] = sum;
120  }
121  for (i = n - 1; i >= 0; i--) {
122  sum = b[i];
123  for (j = i + 1; j < n; j++) sum -= a[i][j]*b[j];
124  b[i] = sum / a[i][i];
125  }
126 }
127 
128 /* ********************************************************************* */
129 void TridiagonalSolve(double *am, double *a0, double *ap, double *b,
130  double *y, int n)
131 /*!
132  * Use recursion formula to solve a tridiagonal system of the type
133  *
134  * am[i]*y[i-1] + a0[i]*y[i] + ap[i]*y[i+1] = b[i]
135  *
136  * from i = 1..n-1.
137  * Boundary coefficients must have been imposed at y[0] and y[n]
138  * On output y[] is replaced with the updated solution.
139  *********************************************************************** */
140 {
141  int i;
142  double alpha[n], beta[n], gamma;
143 
144  alpha[n-1] = 0.0;
145  beta[n-1] = y[n];
146  for (i = n-1; i > 0; i--){
147  gamma = -1.0/(a0[i] + ap[i]*alpha[i]);
148  alpha[i-1] = gamma*am[i];
149  beta[i-1] = gamma*(ap[i]*beta[i] - b[i]);
150  }
151 
152  for (i = 0; i < n-1; i++){
153  y[i+1] = alpha[i]*y[i] + beta[i];
154  }
155 
156 /* Verify solution of tridiagonal matrix */
157 /*
158  double res;
159  for (i = 1; i < n; i++){
160  res = am[i]*phi[i-1] + a0[i]*phi[i] + ap[i]*phi[i+1] - b[i];
161  if (fabs(res) > 1.e-9){
162  cout << "! TridiagonalSolve: not correct" << endl;
163  exit(1);
164  }
165  }
166 */
167 }
168 
void FreeArray1D(void *v)
Definition: arrays.c:37
static double alpha
Definition: init.c:3
static double a
Definition: init.c:135
static int n
Definition: analysis.c:3
void TridiagonalSolve(double *am, double *a0, double *ap, double *b, double *y, int n)
void LUBackSubst(double **a, int n, int *indx, double b[])
int j
Definition: analysis.c:2
int k
Definition: analysis.c:2
PLUTO main header file.
#define ARRAY_1D(nx, type)
Definition: prototypes.h:170
#define TINY
int i
Definition: analysis.c:2
int LUDecompose(double **a, int n, int *indx, double *d)