jacobirot.h

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
00020  *************************************************************************************/
00021 
00022 /* Jacobi Transformation of a Symmetric Matrix {{{
00023  *
00024  * Numerical evaluation of eigenvalues and eigenvectors for 3x3 symmetric
00025  * matrices using the Jacobi-rotation Method.
00026  *
00027  * 2005-09-01 (C): Dorival M. Pedroso (Expanded all loops; Using tensor Tensor2 (Mandel))
00028  * 2005-05-10 (C): Dorival M. Pedroso (C++)
00029  * 2004-08-15 (C): Dorival M. Pedroso (Fortran 95)
00030  * 2002-04-15 (C): Dorival M. Pedroso (Fortran 77)
00031  *
00032  * The Jacobi method consists of a sequence of orthogonal similarity transformations.
00033  * Each transformation (a Jacobi rotation) is just a plane rotation designed to annihilate one of the off-diagonal matrix elements.
00034  * Successive transformations undo previously set zeros, but the off-diagonal elements nevertheless get smaller and smaller.
00035  * Accumulating the product of the transformations as you go gives the matrix (Q) of eigenvectors (V), while the elements of the final
00036  * diagonal matrix (A) are the eigenvalues (L).
00037  * The Jacobi method is absolutely foolproof for all real symmetric matrices.
00038  * For matrices of order greater than about 10, say, the algorithm is slower, by a significant constant factor, than the QR method.
00039  *       _      _         _      _         _      _ 
00040  *      | Q(0,0) |       | Q(0,1) |       | Q(0,2) |
00041  *  V0= | Q(1,0) |   V1= | Q(1,1) |   V2= | Q(1,2) |
00042  *      | Q(2,0) |       | Q(2,1) |       | Q(2,2) |
00043  *       -      -         -      -         -      - 
00044  }}} */
00045 
00046 #ifndef MECHSYS_TENSORS_JACOBIROT_H
00047 #define MECHSYS_TENSORS_JACOBIROT_H
00048 
00049 #ifdef HAVE_CONFIG_H
00050   #include "config.h"
00051 #else
00052   #ifndef REAL
00053     #define REAL double
00054   #endif
00055 #endif
00056 
00057 #include <cmath> // for sqrt()
00058 
00059 #include "tensors/tensors.h"
00060 
00061 namespace Tensors
00062 {
00063 
00068 
00069 
00078 int JacobiRot(Tensor2 const & T    , 
00079               REAL            V0[3], 
00080               REAL            V1[3], 
00081               REAL            V2[3], 
00082               REAL            L[3]); 
00083 
00085 
00086 int JacobiRot(Tensor2 const & T    , 
00087               REAL            L[3]); 
00088  // end of group TensorJacobiRot
00090 
00091 
00093 
00094 
00095 inline int JacobiRot(Tensor2 const & T, REAL V0[3], REAL V1[3], REAL V2[3], REAL L[3])  // {{{
00096 {
00097     const REAL maxIt=30;       // Max number of iterations
00098     const REAL errTol=1.0e-15; // Erro: Tolerance
00099     const REAL ZERO=1.0e-10;   // Erro: Tolerance
00100     
00101     REAL UT[3];         // Values of the Upper Triangle part of symmetric matrix A
00102     REAL th;            // theta = (Aii-Ajj)/2Aij
00103     REAL c;             // Cossine
00104     REAL s;             // Sine
00105     REAL cc;            // Cossine squared
00106     REAL ss;            // Sine squared
00107     REAL t;             // Tangent
00108     REAL Temp;          // Auxiliar variable
00109     REAL TM[3];         // Auxiliar array
00110     REAL sq2=sqrt(2.0); // Useful for the conversion: Tensor (Mandel) ==> matriz A
00111     REAL sumUT;         // Sum of upper triangle of abs(A) that measures the error
00112     int  it;            // Iteration number
00113     REAL h;             // Difference L[i]-L[j]
00114     
00115     // Initialize eigenvalues which correnspond to the diagonal part of A
00116     L[0]=T(0); L[1]=T(1); L[2]=T(2);
00117 
00118     // Initialize Upper Triangle part of A matrix (array[3])
00119     UT[0]=T(3)/sq2; UT[1]=T(4)/sq2; UT[2]=T(5)/sq2;
00120 
00121     // Initialize eigenvectors
00122     V0[0]=1.0; V1[0]=0.0; V2[0]=0.0;
00123     V0[1]=0.0; V1[1]=1.0; V2[1]=0.0;
00124     V0[2]=0.0; V1[2]=0.0; V2[2]=1.0;
00125 
00126     // Iterations
00127     for (it=1; it<=maxIt; ++it)
00128     {
00129         // Check error
00130         sumUT = fabs(UT[0])+fabs(UT[1])+fabs(UT[2]);
00131         if (sumUT<=errTol) return it;
00132         
00133         // i=0, j=1 ,r=2 (p=3)
00134         h=L[0]-L[1];
00135         if (fabs(h)<ZERO) t=1.0;
00136         else
00137         {
00138             th=0.5*h/UT[0];
00139             t=1.0/(fabs(th)+sqrt(th*th+1.0));
00140             if (th<0.0) t=-t;
00141         }
00142         c  = 1.0/sqrt(1.0+t*t);
00143         s  = c*t;
00144         cc = c*c;
00145         ss = s*s;
00146         // Zeroes term UT[0]
00147         Temp  = cc*L[0] + 2.0*c*s*UT[0] + ss*L[1];
00148         L[1]  = ss*L[0] - 2.0*c*s*UT[0] + cc*L[1];
00149         L[0]  = Temp;
00150         UT[0] = 0.0;
00151         Temp  = c*UT[2] + s*UT[1];
00152         UT[1] = c*UT[1] - s*UT[2];
00153         UT[2] = Temp;
00154         // Actualize eigenvectors
00155         TM[0] = s*V1[0] + c*V0[0];
00156         TM[1] = s*V1[1] + c*V0[1];
00157         TM[2] = s*V1[2] + c*V0[2];
00158         V1[0] = c*V1[0] - s*V0[0];
00159         V1[1] = c*V1[1] - s*V0[1];
00160         V1[2] = c*V1[2] - s*V0[2];
00161         V0[0] = TM[0];
00162         V0[1] = TM[1];
00163         V0[2] = TM[2];
00164         
00165         // i=1, j=2 ,r=0 (p=4)
00166         h = L[1]-L[2];
00167         if (fabs(h)<ZERO) t=1.0;
00168         else
00169         {
00170             th=0.5*h/UT[1];
00171             t=1.0/(fabs(th)+sqrt(th*th+1.0));
00172             if (th<0.0) t=-t;
00173         }
00174         c  = 1.0/sqrt(1.0+t*t);
00175         s  = c*t;
00176         cc = c*c;
00177         ss = s*s;
00178         // Zeroes term UT[1]
00179         Temp  = cc*L[1] + 2.0*c*s*UT[1] + ss*L[2];
00180         L[2]  = ss*L[1] - 2.0*c*s*UT[1] + cc*L[2];
00181         L[1]  = Temp;
00182         UT[1] = 0.0;
00183         Temp  = c*UT[0] + s*UT[2];
00184         UT[2] = c*UT[2] - s*UT[0];
00185         UT[0] = Temp;
00186         // Actualize eigenvectors
00187         TM[1] = s*V2[1] + c*V1[1];
00188         TM[2] = s*V2[2] + c*V1[2];
00189         TM[0] = s*V2[0] + c*V1[0];
00190         V2[1] = c*V2[1] - s*V1[1];
00191         V2[2] = c*V2[2] - s*V1[2];
00192         V2[0] = c*V2[0] - s*V1[0];
00193         V1[1] = TM[1];
00194         V1[2] = TM[2];
00195         V1[0] = TM[0];
00196 
00197         // i=0, j=2 ,r=1 (p=5)
00198         h = L[0]-L[2];
00199         if (fabs(h)<ZERO) t=1.0;
00200         else
00201         {
00202             th=0.5*h/UT[2];
00203             t=1.0/(fabs(th)+sqrt(th*th+1.0));
00204             if (th<0.0) t=-t;
00205         }
00206         c  = 1.0/sqrt(1.0+t*t);
00207         s  = c*t;
00208         cc = c*c;
00209         ss = s*s;
00210         // Zeroes term UT[2]
00211         Temp  = cc*L[0] + 2.0*c*s*UT[2] + ss*L[2];
00212         L[2]  = ss*L[0] - 2.0*c*s*UT[2] + cc*L[2];
00213         L[0]  = Temp;
00214         UT[2] = 0.0;
00215         Temp  = c*UT[0] + s*UT[1];
00216         UT[1] = c*UT[1] - s*UT[0];
00217         UT[0] = Temp;
00218         // Actualize eigenvectors
00219         TM[0] = s*V2[0] + c*V0[0];
00220         TM[2] = s*V2[2] + c*V0[2];
00221         TM[1] = s*V2[1] + c*V0[1];
00222         V2[0] = c*V2[0] - s*V0[0];
00223         V2[2] = c*V2[2] - s*V0[2];
00224         V2[1] = c*V2[1] - s*V0[1];
00225         V0[0] = TM[0];
00226         V0[2] = TM[2];
00227         V0[1] = TM[1];
00228     }
00229 
00230     return -1; // Did not converge
00231 
00232 } // }}}
00233 
00234 inline int JacobiRot(Tensor2 const & T, REAL L[3]) // {{{
00235 {
00236     const REAL maxIt=30;       // Max number of iterations
00237     const REAL errTol=1.0e-15; // Erro: Tolerance
00238     const REAL ZERO=1.0e-10;   // Erro: Tolerance
00239     
00240     REAL UT[3];         // Values of the Upper Triangle part of symmetric matrix A
00241     REAL th;            // theta = (Aii-Ajj)/2Aij
00242     REAL c;             // Cossine
00243     REAL s;             // Sine
00244     REAL cc;            // Cossine squared
00245     REAL ss;            // Sine squared
00246     REAL t;             // Tangent
00247     REAL Temp;          // Auxiliar variable
00248     REAL sq2=sqrt(2.0); // Useful for the conversion: Tensor (Mandel) ==> matriz A
00249     REAL sumUT;         // Sum of upper triangle of abs(A) that measures the error
00250     int  it;            // Iteration number
00251     REAL h;             // Difference L[i]-L[j]
00252     
00253     // Initialize eigenvalues which correnspond to the diagonal part of A
00254     L[0]=T(0); L[1]=T(1); L[2]=T(2);
00255 
00256     // Initialize Upper Triangle part of A matrix (array[3])
00257     UT[0]=T(3)/sq2; UT[1]=T(4)/sq2; UT[2]=T(5)/sq2;
00258 
00259     // Iterations
00260     for (it=1; it<=maxIt; ++it)
00261     {
00262         // Check error
00263         sumUT = fabs(UT[0])+fabs(UT[1])+fabs(UT[2]);
00264         if (sumUT<=errTol) return it;
00265         
00266         // i=0, j=1 ,r=2 (p=3)
00267         h=L[0]-L[1];
00268         if (fabs(h)<ZERO) t=1.0;
00269         else
00270         {
00271             th=0.5*h/UT[0];
00272             t=1.0/(fabs(th)+sqrt(th*th+1.0));
00273             if (th<0.0) t=-t;
00274         }
00275         c  = 1.0/sqrt(1.0+t*t);
00276         s  = c*t;
00277         cc = c*c;
00278         ss = s*s;
00279         // Zeroes term UT[0]
00280         Temp  = cc*L[0] + 2.0*c*s*UT[0] + ss*L[1];
00281         L[1]  = ss*L[0] - 2.0*c*s*UT[0] + cc*L[1];
00282         L[0]  = Temp;
00283         UT[0] = 0.0;
00284         Temp  = c*UT[2] + s*UT[1];
00285         UT[1] = c*UT[1] - s*UT[2];
00286         UT[2] = Temp;
00287         
00288         // i=1, j=2 ,r=0 (p=4)
00289         h = L[1]-L[2];
00290         if (fabs(h)<ZERO) t=1.0;
00291         else
00292         {
00293             th=0.5*h/UT[1];
00294             t=1.0/(fabs(th)+sqrt(th*th+1.0));
00295             if (th<0.0) t=-t;
00296         }
00297         c  = 1.0/sqrt(1.0+t*t);
00298         s  = c*t;
00299         cc = c*c;
00300         ss = s*s;
00301         // Zeroes term UT[1]
00302         Temp  = cc*L[1] + 2.0*c*s*UT[1] + ss*L[2];
00303         L[2]  = ss*L[1] - 2.0*c*s*UT[1] + cc*L[2];
00304         L[1]  = Temp;
00305         UT[1] = 0.0;
00306         Temp  = c*UT[0] + s*UT[2];
00307         UT[2] = c*UT[2] - s*UT[0];
00308         UT[0] = Temp;
00309 
00310         // i=0, j=2 ,r=1 (p=5)
00311         h = L[0]-L[2];
00312         if (fabs(h)<ZERO) t=1.0;
00313         else
00314         {
00315             th=0.5*h/UT[2];
00316             t=1.0/(fabs(th)+sqrt(th*th+1.0));
00317             if (th<0.0) t=-t;
00318         }
00319         c  = 1.0/sqrt(1.0+t*t);
00320         s  = c*t;
00321         cc = c*c;
00322         ss = s*s;
00323         // Zeroes term UT[2]
00324         Temp  = cc*L[0] + 2.0*c*s*UT[2] + ss*L[2];
00325         L[2]  = ss*L[0] - 2.0*c*s*UT[2] + cc*L[2];
00326         L[0]  = Temp;
00327         UT[2] = 0.0;
00328         Temp  = c*UT[0] + s*UT[1];
00329         UT[1] = c*UT[1] - s*UT[0];
00330         UT[0] = Temp;
00331     }
00332 
00333     return -1; // Did not converge
00334 
00335 } // }}}
00336 
00337 }; // namespace Tensors
00338 
00339 #endif // MECHSYS_TENSORS_JACOBIROT_H
00340 
00341 // vim:fdm=marker

Generated on Wed Jan 24 15:56:26 2007 for MechSys by  doxygen 1.4.7