ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-1.0/libmdtools/MatVec3.c
Revision: 1419
Committed: Tue Jul 27 18:14:16 2004 UTC (19 years, 11 months ago) by gezelter
Content type: text/plain
File size: 12717 byte(s)
Log Message:
BASS eradication project (part 3)

File Contents

# Content
1 #include <stdio.h>
2 #include <math.h>
3 #include <stdlib.h>
4 #include "MatVec3.h"
5
6 /*
7 * Contains various utilities for dealing with 3x3 matrices and
8 * length 3 vectors
9 */
10
11 void identityMat3(double A[3][3]) {
12 int i;
13 for (i = 0; i < 3; i++) {
14 A[i][0] = A[i][1] = A[i][2] = 0.0;
15 A[i][i] = 1.0;
16 }
17 }
18
19 void swapVectors3(double v1[3], double v2[3]) {
20 int i;
21 for (i = 0; i < 3; i++) {
22 double tmp = v1[i];
23 v1[i] = v2[i];
24 v2[i] = tmp;
25 }
26 }
27
28 double normalize3(double x[3]) {
29 double den;
30 int i;
31 if ( (den = norm3(x)) != 0.0 ) {
32 for (i=0; i < 3; i++)
33 {
34 x[i] /= den;
35 }
36 }
37 return den;
38 }
39
40 void matMul3(double a[3][3], double b[3][3], double c[3][3]) {
41 double r00, r01, r02, r10, r11, r12, r20, r21, r22;
42
43 r00 = a[0][0]*b[0][0] + a[0][1]*b[1][0] + a[0][2]*b[2][0];
44 r01 = a[0][0]*b[0][1] + a[0][1]*b[1][1] + a[0][2]*b[2][1];
45 r02 = a[0][0]*b[0][2] + a[0][1]*b[1][2] + a[0][2]*b[2][2];
46
47 r10 = a[1][0]*b[0][0] + a[1][1]*b[1][0] + a[1][2]*b[2][0];
48 r11 = a[1][0]*b[0][1] + a[1][1]*b[1][1] + a[1][2]*b[2][1];
49 r12 = a[1][0]*b[0][2] + a[1][1]*b[1][2] + a[1][2]*b[2][2];
50
51 r20 = a[2][0]*b[0][0] + a[2][1]*b[1][0] + a[2][2]*b[2][0];
52 r21 = a[2][0]*b[0][1] + a[2][1]*b[1][1] + a[2][2]*b[2][1];
53 r22 = a[2][0]*b[0][2] + a[2][1]*b[1][2] + a[2][2]*b[2][2];
54
55 c[0][0] = r00; c[0][1] = r01; c[0][2] = r02;
56 c[1][0] = r10; c[1][1] = r11; c[1][2] = r12;
57 c[2][0] = r20; c[2][1] = r21; c[2][2] = r22;
58 }
59
60 void matVecMul3(double m[3][3], double inVec[3], double outVec[3]) {
61 double a0, a1, a2;
62
63 a0 = inVec[0]; a1 = inVec[1]; a2 = inVec[2];
64
65 outVec[0] = m[0][0]*a0 + m[0][1]*a1 + m[0][2]*a2;
66 outVec[1] = m[1][0]*a0 + m[1][1]*a1 + m[1][2]*a2;
67 outVec[2] = m[2][0]*a0 + m[2][1]*a1 + m[2][2]*a2;
68 }
69
70 double matDet3(double a[3][3]) {
71 int i, j, k;
72 double determinant;
73
74 determinant = 0.0;
75
76 for(i = 0; i < 3; i++) {
77 j = (i+1)%3;
78 k = (i+2)%3;
79
80 determinant += a[0][i] * (a[1][j]*a[2][k] - a[1][k]*a[2][j]);
81 }
82
83 return determinant;
84 }
85
86 void invertMat3(double a[3][3], double b[3][3]) {
87
88 int i, j, k, l, m, n;
89 double determinant;
90
91 determinant = matDet3( a );
92
93 if (determinant == 0.0) {
94 sprintf( painCave.errMsg,
95 "Can't invert a matrix with a zero determinant!\n");
96 painCave.isFatal = 1;
97 simError();
98 }
99
100 for (i=0; i < 3; i++) {
101 j = (i+1)%3;
102 k = (i+2)%3;
103 for(l = 0; l < 3; l++) {
104 m = (l+1)%3;
105 n = (l+2)%3;
106
107 b[l][i] = (a[j][m]*a[k][n] - a[j][n]*a[k][m]) / determinant;
108 }
109 }
110 }
111
112 void transposeMat3(double in[3][3], double out[3][3]) {
113 double temp[3][3];
114 int i, j;
115
116 for (i = 0; i < 3; i++) {
117 for (j = 0; j < 3; j++) {
118 temp[j][i] = in[i][j];
119 }
120 }
121 for (i = 0; i < 3; i++) {
122 for (j = 0; j < 3; j++) {
123 out[i][j] = temp[i][j];
124 }
125 }
126 }
127
128 void printMat3(double A[3][3] ){
129
130 fprintf(stderr, "[ %g, %g, %g ]\n[ %g, %g, %g ]\n[ %g, %g, %g ]\n",
131 A[0][0] , A[0][1] , A[0][2],
132 A[1][0] , A[1][1] , A[1][2],
133 A[2][0] , A[2][1] , A[2][2]) ;
134 }
135
136 void printMat9(double A[9] ){
137
138 fprintf(stderr, "[ %g, %g, %g ]\n[ %g, %g, %g ]\n[ %g, %g, %g ]\n",
139 A[0], A[1], A[2],
140 A[3], A[4], A[5],
141 A[6], A[7], A[8]);
142 }
143
144 double matTrace3(double m[3][3]){
145 double trace;
146 trace = m[0][0] + m[1][1] + m[2][2];
147
148 return trace;
149 }
150
151 void crossProduct3(double a[3],double b[3], double out[3]){
152
153 out[0] = a[1] * b[2] - a[2] * b[1];
154 out[1] = a[2] * b[0] - a[0] * b[2] ;
155 out[2] = a[0] * b[1] - a[1] * b[0];
156
157 }
158
159 double dotProduct3(double a[3], double b[3]){
160 return a[0]*b[0] + a[1]*b[1]+ a[2]*b[2];
161 }
162
163 //----------------------------------------------------------------------------
164 // Extract the eigenvalues and eigenvectors from a 3x3 matrix.
165 // The eigenvectors (the columns of V) will be normalized.
166 // The eigenvectors are aligned optimally with the x, y, and z
167 // axes respectively.
168
169 void diagonalize3x3(const double A[3][3], double w[3], double V[3][3]) {
170 int i,j,k,maxI;
171 double tmp, maxVal;
172
173 // do the matrix[3][3] to **matrix conversion for Jacobi
174 double C[3][3];
175 double *ATemp[3],*VTemp[3];
176 for (i = 0; i < 3; i++)
177 {
178 C[i][0] = A[i][0];
179 C[i][1] = A[i][1];
180 C[i][2] = A[i][2];
181 ATemp[i] = C[i];
182 VTemp[i] = V[i];
183 }
184
185 // diagonalize using Jacobi
186 JacobiN(ATemp,3,w,VTemp);
187
188 // if all the eigenvalues are the same, return identity matrix
189 if (w[0] == w[1] && w[0] == w[2])
190 {
191 identityMat3(V);
192 return;
193 }
194
195 // transpose temporarily, it makes it easier to sort the eigenvectors
196 transposeMat3(V,V);
197
198 // if two eigenvalues are the same, re-orthogonalize to optimally line
199 // up the eigenvectors with the x, y, and z axes
200 for (i = 0; i < 3; i++)
201 {
202 if (w[(i+1)%3] == w[(i+2)%3]) // two eigenvalues are the same
203 {
204 // find maximum element of the independant eigenvector
205 maxVal = fabs(V[i][0]);
206 maxI = 0;
207 for (j = 1; j < 3; j++)
208 {
209 if (maxVal < (tmp = fabs(V[i][j])))
210 {
211 maxVal = tmp;
212 maxI = j;
213 }
214 }
215 // swap the eigenvector into its proper position
216 if (maxI != i)
217 {
218 tmp = w[maxI];
219 w[maxI] = w[i];
220 w[i] = tmp;
221 swapVectors3(V[i],V[maxI]);
222 }
223 // maximum element of eigenvector should be positive
224 if (V[maxI][maxI] < 0)
225 {
226 V[maxI][0] = -V[maxI][0];
227 V[maxI][1] = -V[maxI][1];
228 V[maxI][2] = -V[maxI][2];
229 }
230
231 // re-orthogonalize the other two eigenvectors
232 j = (maxI+1)%3;
233 k = (maxI+2)%3;
234
235 V[j][0] = 0.0;
236 V[j][1] = 0.0;
237 V[j][2] = 0.0;
238 V[j][j] = 1.0;
239 crossProduct3(V[maxI],V[j],V[k]);
240 normalize3(V[k]);
241 crossProduct3(V[k],V[maxI],V[j]);
242
243 // transpose vectors back to columns
244 transposeMat3(V,V);
245 return;
246 }
247 }
248
249 // the three eigenvalues are different, just sort the eigenvectors
250 // to align them with the x, y, and z axes
251
252 // find the vector with the largest x element, make that vector
253 // the first vector
254 maxVal = fabs(V[0][0]);
255 maxI = 0;
256 for (i = 1; i < 3; i++)
257 {
258 if (maxVal < (tmp = fabs(V[i][0])))
259 {
260 maxVal = tmp;
261 maxI = i;
262 }
263 }
264 // swap eigenvalue and eigenvector
265 if (maxI != 0)
266 {
267 tmp = w[maxI];
268 w[maxI] = w[0];
269 w[0] = tmp;
270 swapVectors3(V[maxI],V[0]);
271 }
272 // do the same for the y element
273 if (fabs(V[1][1]) < fabs(V[2][1]))
274 {
275 tmp = w[2];
276 w[2] = w[1];
277 w[1] = tmp;
278 swapVectors3(V[2],V[1]);
279 }
280
281 // ensure that the sign of the eigenvectors is correct
282 for (i = 0; i < 2; i++)
283 {
284 if (V[i][i] < 0)
285 {
286 V[i][0] = -V[i][0];
287 V[i][1] = -V[i][1];
288 V[i][2] = -V[i][2];
289 }
290 }
291 // set sign of final eigenvector to ensure that determinant is positive
292 if (matDet3(V) < 0)
293 {
294 V[2][0] = -V[2][0];
295 V[2][1] = -V[2][1];
296 V[2][2] = -V[2][2];
297 }
298
299 // transpose the eigenvectors back again
300 transposeMat3(V,V);
301 }
302
303
304 #define MAT_ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau); a[k][l]=h+s*(g-h*tau);
305
306 #define MAX_ROTATIONS 20
307
308 // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn
309 // real symmetric matrix. Square nxn matrix a; size of matrix in n;
310 // output eigenvalues in w; and output eigenvectors in v. Resulting
311 // eigenvalues/vectors are sorted in decreasing order; eigenvectors are
312 // normalized.
313 int JacobiN(double **a, int n, double *w, double **v) {
314
315 int i, j, k, iq, ip, numPos;
316 int ceil_half_n;
317 double tresh, theta, tau, t, sm, s, h, g, c, tmp;
318 double bspace[4], zspace[4];
319 double *b = bspace;
320 double *z = zspace;
321
322
323 // only allocate memory if the matrix is large
324 if (n > 4)
325 {
326 b = (double *) calloc(n, sizeof(double));
327 z = (double *) calloc(n, sizeof(double));
328 }
329
330 // initialize
331 for (ip=0; ip<n; ip++)
332 {
333 for (iq=0; iq<n; iq++)
334 {
335 v[ip][iq] = 0.0;
336 }
337 v[ip][ip] = 1.0;
338 }
339 for (ip=0; ip<n; ip++)
340 {
341 b[ip] = w[ip] = a[ip][ip];
342 z[ip] = 0.0;
343 }
344
345 // begin rotation sequence
346 for (i=0; i<MAX_ROTATIONS; i++)
347 {
348 sm = 0.0;
349 for (ip=0; ip<n-1; ip++)
350 {
351 for (iq=ip+1; iq<n; iq++)
352 {
353 sm += fabs(a[ip][iq]);
354 }
355 }
356 if (sm == 0.0)
357 {
358 break;
359 }
360
361 if (i < 3) // first 3 sweeps
362 {
363 tresh = 0.2*sm/(n*n);
364 }
365 else
366 {
367 tresh = 0.0;
368 }
369
370 for (ip=0; ip<n-1; ip++)
371 {
372 for (iq=ip+1; iq<n; iq++)
373 {
374 g = 100.0*fabs(a[ip][iq]);
375
376 // after 4 sweeps
377 if (i > 3 && (fabs(w[ip])+g) == fabs(w[ip])
378 && (fabs(w[iq])+g) == fabs(w[iq]))
379 {
380 a[ip][iq] = 0.0;
381 }
382 else if (fabs(a[ip][iq]) > tresh)
383 {
384 h = w[iq] - w[ip];
385 if ( (fabs(h)+g) == fabs(h))
386 {
387 t = (a[ip][iq]) / h;
388 }
389 else
390 {
391 theta = 0.5*h / (a[ip][iq]);
392 t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
393 if (theta < 0.0)
394 {
395 t = -t;
396 }
397 }
398 c = 1.0 / sqrt(1+t*t);
399 s = t*c;
400 tau = s/(1.0+c);
401 h = t*a[ip][iq];
402 z[ip] -= h;
403 z[iq] += h;
404 w[ip] -= h;
405 w[iq] += h;
406 a[ip][iq]=0.0;
407
408 // ip already shifted left by 1 unit
409 for (j = 0;j <= ip-1;j++)
410 {
411 MAT_ROTATE(a,j,ip,j,iq)
412 }
413 // ip and iq already shifted left by 1 unit
414 for (j = ip+1;j <= iq-1;j++)
415 {
416 MAT_ROTATE(a,ip,j,j,iq)
417 }
418 // iq already shifted left by 1 unit
419 for (j=iq+1; j<n; j++)
420 {
421 MAT_ROTATE(a,ip,j,iq,j)
422 }
423 for (j=0; j<n; j++)
424 {
425 MAT_ROTATE(v,j,ip,j,iq)
426 }
427 }
428 }
429 }
430
431 for (ip=0; ip<n; ip++)
432 {
433 b[ip] += z[ip];
434 w[ip] = b[ip];
435 z[ip] = 0.0;
436 }
437 }
438
439 //// this is NEVER called
440 if ( i >= MAX_ROTATIONS )
441 {
442 sprintf( painCave.errMsg,
443 "Jacobi: Error extracting eigenfunctions!\n");
444 painCave.isFatal = 1;
445 simError();
446 return 0;
447 }
448
449 // sort eigenfunctions these changes do not affect accuracy
450 for (j=0; j<n-1; j++) // boundary incorrect
451 {
452 k = j;
453 tmp = w[k];
454 for (i=j+1; i<n; i++) // boundary incorrect, shifted already
455 {
456 if (w[i] >= tmp) // why exchage if same?
457 {
458 k = i;
459 tmp = w[k];
460 }
461 }
462 if (k != j)
463 {
464 w[k] = w[j];
465 w[j] = tmp;
466 for (i=0; i<n; i++)
467 {
468 tmp = v[i][j];
469 v[i][j] = v[i][k];
470 v[i][k] = tmp;
471 }
472 }
473 }
474 // insure eigenvector consistency (i.e., Jacobi can compute vectors that
475 // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can
476 // reek havoc in hyperstreamline/other stuff. We will select the most
477 // positive eigenvector.
478 ceil_half_n = (n >> 1) + (n & 1);
479 for (j=0; j<n; j++)
480 {
481 for (numPos=0, i=0; i<n; i++)
482 {
483 if ( v[i][j] >= 0.0 )
484 {
485 numPos++;
486 }
487 }
488 // if ( numPos < ceil(double(n)/double(2.0)) )
489 if ( numPos < ceil_half_n)
490 {
491 for(i=0; i<n; i++)
492 {
493 v[i][j] *= -1.0;
494 }
495 }
496 }
497
498 if (n > 4)
499 {
500 free(b);
501 free(z);
502 }
503 return 1;
504 }
505
506 #undef MAT_ROTATE
507 #undef MAX_ROTATIONS