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

# User Rev Content
1 gezelter 1334 #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 gezelter 1348 int ceil_half_n;
318 gezelter 1334 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 gezelter 1348
323 gezelter 1334
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 gezelter 1348 ceil_half_n = (n >> 1) + (n & 1);
480 gezelter 1334 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