ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-1.0/libmdtools/MatVec3.c
Revision: 1348
Committed: Mon Jul 19 16:47:57 2004 UTC (19 years, 11 months ago) by gezelter
Content type: text/plain
File size: 12739 byte(s)
Log Message:
*** empty log message ***

File Contents

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