ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-3.0/src/math/MatVec3.c
Revision: 2263
Committed: Wed Jul 13 15:54:00 2005 UTC (18 years, 11 months ago) by tim
Content type: text/plain
File size: 14896 byte(s)
Log Message:
replace c++ style comment in c files

File Contents

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