ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/group/trunk/OOPSE-2.0/src/math/MatVec3.c
Revision: 1930
Committed: Wed Jan 12 22:41:40 2005 UTC (19 years, 5 months ago) by gezelter
Content type: text/plain
File size: 14799 byte(s)
Log Message:
merging new_design branch into OOPSE-2.0

File Contents

# User Rev Content
1 gezelter 1930 /*
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 gezelter 1490 #include <stdio.h>
43     #include <math.h>
44     #include <stdlib.h>
45 tim 1492 #include "math/MatVec3.h"
46 gezelter 1490
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