ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/oopse-1.0/libmdtools/MatVec3.c
Revision: 1447
Committed: Fri Jul 30 21:01:35 2004 UTC (19 years, 11 months ago) by gezelter
Content type: text/plain
File size: 12717 byte(s)
Log Message:
Initial import of OOPSE sources into cvs tree

File Contents

# User Rev Content
1 gezelter 1447 #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