ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE/libmdtools/MatVec3.c
Revision: 1097
Committed: Mon Apr 12 20:32:20 2004 UTC (20 years, 2 months ago) by gezelter
Content type: text/plain
File size: 12713 byte(s)
Log Message:
Changes for RigidBody dynamics (Somewhat extensive)

File Contents

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