-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathlu.c
322 lines (231 loc) · 10.3 KB
/
lu.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//Modified by Alexander Tchekhovskoy: MPI+3D
/***********************************************************************************
Copyright 2006 Charles F. Gammie, Jonathan C. McKinney, Scott C. Noble,
Gabor Toth, and Luca Del Zanna
HARM version 1.0 (released May 1, 2006)
This file is part of HARM. HARM is a program that solves hyperbolic
partial differential equations in conservative form using high-resolution
shock-capturing techniques. This version of HARM has been configured to
solve the relativistic magnetohydrodynamic equations of motion on a
stationary black hole spacetime in Kerr-Schild coordinates to evolve
an accretion disk model.
You are morally obligated to cite the following two papers in his/her
scientific literature that results from use of any part of HARM:
[1] Gammie, C. F., McKinney, J. C., \& Toth, G.\ 2003,
Astrophysical Journal, 589, 444.
[2] Noble, S. C., Gammie, C. F., McKinney, J. C., \& Del Zanna, L. \ 2006,
Astrophysical Journal, 641, 626.
Further, we strongly encourage you to obtain the latest version of
HARM directly from our distribution website:
http://rainman.astro.uiuc.edu/codelib/
HARM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
HARM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with HARM; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
***********************************************************************************/
#include "decs.h"
/*************************************************************************/
/*************************************************************************
invert_matrix():
Uses LU decomposition and back substitution to invert a matrix
A[][] and assigns the inverse to Ainv[][]. This routine does not
destroy the original matrix A[][].
Returns (1) if a singular matrix is found, (0) otherwise.
*************************************************************************/
int invert_matrix( double Am[][NDIM], double Aminv[][NDIM] )
{
int i,j;
int n = NDIM;
int permute[NDIM];
double dxm[NDIM], Amtmp[NDIM][NDIM];
for( i = 0 ; i < NDIM*NDIM ; i++ ) { Amtmp[0][i] = Am[0][i]; }
// Get the LU matrix:
if( LU_decompose( Amtmp, permute ) != 0 ) {
fprintf(stderr, "invert_matrix(): singular matrix encountered! \n");
return(1);
}
for( i = 0; i < n; i++ ) {
for( j = 0 ; j < n ; j++ ) { dxm[j] = 0. ; }
dxm[i] = 1.;
/* Solve the linear system for the i^th column of the inverse matrix: : */
LU_substitution( Amtmp, dxm, permute );
for( j = 0 ; j < n ; j++ ) { Aminv[j][i] = dxm[j]; }
}
return(0);
}
/*************************************************************************/
/*************************************************************************
LU_decompose():
Performs a LU decomposition of the matrix A using Crout's method
with partial implicit pivoting. The exact LU decomposition of the
matrix can be reconstructed from the resultant row-permuted form via
the integer array permute[]
The algorithm closely follows ludcmp.c of "Numerical Recipes
in C" by Press et al. 1992.
This will be used to solve the linear system A.x = B
Returns (1) if a singular matrix is found, (0) otherwise.
*************************************************************************/
int LU_decompose( double A[][NDIM], int permute[] )
{
const double absmin = 1.e-30; /* Value used instead of 0 for singular matrices */
static double row_norm[NDIM];
double absmax, maxtemp, mintemp;
int i, j, k, max_row;
int n = NDIM;
max_row = 0;
/* Find the maximum elements per row so that we can pretend later
we have unit-normalized each equation: */
for( i = 0; i < n; i++ ) {
absmax = 0.;
for( j = 0; j < n ; j++ ) {
maxtemp = fabs( A[i][j] );
if( maxtemp > absmax ) {
absmax = maxtemp;
}
}
/* Make sure that there is at least one non-zero element in this row: */
if( absmax == 0. ) {
fprintf(stderr, "LU_decompose(): row-wise singular matrix!\n");
return(1);
}
row_norm[i] = 1. / absmax ; /* Set the row's normalization factor. */
}
/* The following the calculates the matrix composed of the sum
of the lower (L) tridagonal matrix and the upper (U) tridagonal
matrix that, when multiplied, form the original maxtrix.
This is what we call the LU decomposition of the maxtrix.
It does this by a recursive procedure, starting from the
upper-left, proceding down the column, and then to the next
column to the right. The decomposition can be done in place
since element {i,j} require only those elements with {<=i,<=j}
which have already been computed.
See pg. 43-46 of "Num. Rec." for a more thorough description.
*/
/* For each of the columns, starting from the left ... */
for( j = 0; j < n; j++ ) {
/* For each of the rows starting from the top.... */
/* Calculate the Upper part of the matrix: i < j : */
for( i = 0; i < j; i++ ) {
for( k = 0; k < i; k++ ) {
A[i][j] -= A[i][k] * A[k][j];
}
}
absmax = 0.0;
/* Calculate the Lower part of the matrix: i <= j : */
for( i = j; i < n; i++ ) {
for (k = 0; k < j; k++) {
A[i][j] -= A[i][k] * A[k][j];
}
/* Find the maximum element in the column given the implicit
unit-normalization (represented by row_norm[i]) of each row:
*/
maxtemp = fabs(A[i][j]) * row_norm[i] ;
if( maxtemp >= absmax ) {
absmax = maxtemp;
max_row = i;
}
}
/* Swap the row with the largest element (of column j) with row_j. absmax
This is the partial pivoting procedure that ensures we don't divide
by 0 (or a small number) when we solve the linear system.
Also, since the procedure starts from left-right/top-bottom,
the pivot values are chosen from a pool involving all the elements
of column_j in rows beneath row_j. This ensures that
a row is not permuted twice, which would mess things up.
*/
if( max_row != j ) {
/* Don't swap if it will send a 0 to the last diagonal position.
Note that the last column cannot pivot with any other row,
so this is the last chance to ensure that the last two
columns have non-zero diagonal elements.
*/
if( (j == (n-2)) && (A[j][j+1] == 0.) ) {
max_row = j;
}
else {
for( k = 0; k < n; k++ ) {
maxtemp = A[ j ][k] ;
A[ j ][k] = A[max_row][k] ;
A[max_row][k] = maxtemp;
}
/* Don't forget to swap the normalization factors, too...
but we don't need the jth element any longer since we
only look at rows beneath j from here on out.
*/
row_norm[max_row] = row_norm[j] ;
}
}
/* Set the permutation record s.t. the j^th element equals the
index of the row swapped with the j^th row. Note that since
this is being done in successive columns, the permutation
vector records the successive permutations and therefore
index of permute[] also indexes the chronology of the
permutations. E.g. permute[2] = {2,1} is an identity
permutation, which cannot happen here though.
*/
permute[j] = max_row;
if( A[j][j] == 0. ) {
A[j][j] = absmin;
}
/* Normalize the columns of the Lower tridiagonal part by their respective
diagonal element. This is not done in the Upper part because the
Lower part's diagonal elements were set to 1, which can be done w/o
any loss of generality.
*/
if( j != (n-1) ) {
maxtemp = 1. / A[j][j] ;
for( i = (j+1) ; i < n; i++ ) {
A[i][j] *= maxtemp;
}
}
}
return(0);
/* End of LU_decompose() */
}
/************************************************************************
LU_substitution():
Performs the forward (w/ the Lower) and backward (w/ the Upper)
substitutions using the LU-decomposed matrix A[][] of the original
matrix A' of the linear equation: A'.x = B. Upon entry, A[][]
is the LU matrix, B[] is the source vector, and permute[] is the
array containing order of permutations taken to the rows of the LU
matrix. See LU_decompose() for further details.
Upon exit, B[] contains the solution x[], A[][] is left unchanged.
************************************************************************/
void LU_substitution( double A[][NDIM], double B[], int permute[] )
{
int i, j ;
int n = NDIM;
double tmpvar,tmpvar2;
/* Perform the forward substitution using the LU matrix.
*/
for(i = 0; i < n; i++) {
/* Before doing the substitution, we must first permute the
B vector to match the permutation of the LU matrix.
Since only the rows above the currrent one matter for
this row, we can permute one at a time.
*/
tmpvar = B[permute[i]];
B[permute[i]] = B[ i ];
for( j = (i-1); j >= 0 ; j-- ) {
tmpvar -= A[i][j] * B[j];
}
B[i] = tmpvar;
}
/* Perform the backward substitution using the LU matrix.
*/
for( i = (n-1); i >= 0; i-- ) {
for( j = (i+1); j < n ; j++ ) {
B[i] -= A[i][j] * B[j];
}
B[i] /= A[i][i] ;
}
/* End of LU_substitution() */
}