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

# 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 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