![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
00001 /************************************************************************ 00002 * MechSys - Open Library for Mechanical Systems * 00003 * Copyright (C) 2005 Dorival M. Pedroso, Raúl D. D. Farfan * 00004 * * 00005 * This program is free software: you can redistribute it and/or modify * 00006 * it under the terms of the GNU General Public License as published by * 00007 * the Free Software Foundation, either version 3 of the License, or * 00008 * any later version. * 00009 * * 00010 * This program is distributed in the hope that it will be useful, * 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00013 * GNU General Public License for more details. * 00014 * * 00015 * You should have received a copy of the GNU General Public License * 00016 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00017 ************************************************************************/ 00018 00019 /* Numerical evaluation of eigenvalues and eigenvectors for NxN SYMMETRIC 00020 * matrices using the Jacobi-rotation Method. 00021 * 00022 * 2005-09-27 (C): Dorival M. Pedroso - Completely rewritten (3x3 => NxN); based on C numerical recipes 00023 * 2005-05-10 (C): Dorival M. Pedroso - C++ 00024 * 2004-08-15 (C): Dorival M. Pedroso - Fortran 95 00025 * 2002-04-15 (C): Dorival M. Pedroso - Fortran 77 00026 */ 00027 00028 #ifndef MECHSYS_LINALG_JACOBIROT_H 00029 #define MECHSYS_LINALG_JACOBIROT_H 00030 00031 // STL 00032 #include <cmath> 00033 00034 // MechSys 00035 #include "mechsys/linalg/matvec.h" 00036 00053 template<typename MatrixType, typename VectorType> 00054 inline int _jacobi_rot (int N, MatrixType & A, MatrixType & Q, VectorType & v, double errTol=DBL_EPSILON) 00055 { 00056 const int maxIt = 20; // max number of iterations 00057 const double Zero = DBL_EPSILON; // tolerance 00058 00059 int j,p,q; 00060 double theta,tau,t,sm,s,h,g,c; 00061 double * b = new double [N]; 00062 double * z = new double [N]; 00063 00064 for (p=0; p<N; p++) // initialize Q to the identity matrix. 00065 { 00066 for (q=0; q<N; q++) Q(p,q) = 0.0; 00067 Q(p,p) = 1.0; 00068 } 00069 for (p=0; p<N; p++) 00070 { 00071 b[p] = v(p) = A(p,p); // initialize b and v to the diagonal of A 00072 z[p] = 0.0; // this vector will accumulate terms of the form tapq as in equation (11.1.14). 00073 } 00074 00075 for (int it=0; it<maxIt; it++) 00076 { 00077 sm = 0.0; 00078 for (p=0; p<N-1; p++) // sum off-diagonal elements. 00079 { 00080 for (q=p+1; q<N; q++) 00081 sm += fabs(A(p,q)); 00082 } 00083 if (sm<errTol) // exit point 00084 { 00085 delete [] b; 00086 delete [] z; 00087 return it+1; 00088 } 00089 for (p=0; p<N-1; p++) 00090 { 00091 for (q=p+1; q<N; q++) 00092 { 00093 h = v(q)-v(p); 00094 if (fabs(h)<=Zero) t=1.0; 00095 else 00096 { 00097 theta = 0.5*h/(A(p,q)); 00098 t = 1.0/(fabs(theta)+sqrt(1.0+theta*theta)); 00099 if (theta < 0.0) t=-t; 00100 } 00101 c = 1.0/sqrt(1.0+t*t); 00102 s = t*c; 00103 tau = s/(1.0+c); 00104 h = t*A(p,q); 00105 z[p] -= h; 00106 z[q] += h; 00107 v(p) -= h; 00108 v(q) += h; 00109 A(p,q) = 0.0; 00110 for (j=0; j<p; j++) // case of rotations 0 <= j < p. 00111 { 00112 g = A(j,p); 00113 h = A(j,q); 00114 A(j,p) = g - s*(h+g*tau); 00115 A(j,q) = h + s*(g-h*tau); 00116 } 00117 for (j=p+1; j<q; j++) // case of rotations p < j < q. 00118 { 00119 g = A(p,j); 00120 h = A(j,q); 00121 A(p,j) = g - s*(h+g*tau); 00122 A(j,q) = h + s*(g-h*tau); 00123 } 00124 for (j=q+1; j<N; j++) //case of rotations q < j < N. 00125 { 00126 g = A(p,j); 00127 h = A(q,j); 00128 A(p,j) = g - s*(h+g*tau); 00129 A(q,j) = h + s*(g-h*tau); 00130 } 00131 for (j=0; j<N; j++) // Q matrix 00132 { 00133 g = Q(j,p); 00134 h = Q(j,q); 00135 Q(j,p) = g - s*(h+g*tau); 00136 Q(j,q) = h + s*(g-h*tau); 00137 } 00138 } 00139 } 00140 for (p=0; p<N; p++) 00141 { 00142 b[p] += z[p]; 00143 z[p] = 0.0; // reinitialize z. 00144 v(p) = b[p]; // update v with the sum of tapq, 00145 } 00146 } 00147 00148 delete [] b; 00149 delete [] z; 00150 throw new Fatal("JacobiRot: Jacobi rotation dit not converge after %d iterations",maxIt+1); 00151 return maxIt+1; 00152 } 00153 00155 inline int JacobiRot (Mat_t & A, Mat_t & Q, Vec_t & v, double errTol=DBL_EPSILON) 00156 { 00157 int N = A.num_rows(); 00158 if (N<2) throw new Fatal("JacobiRot: Matrix needs to be at least 2x2"); 00159 if (A.num_cols()!=(size_t)N) throw new Fatal("JacobiRot: Matrix must be square"); 00160 Q.change_dim (N,N); 00161 v.change_dim (N); 00162 return _jacobi_rot (N, A, Q, v, errTol); 00163 } 00164 00166 inline int JacobiRot (Mat3_t & A, Mat3_t & Q, Vec3_t & v, double errTol=DBL_EPSILON) 00167 { 00168 return _jacobi_rot (/*N*/3, A, Q, v, errTol); 00169 } 00170 00172 inline int JacobiRot (Vec_t const & TenA, Mat3_t & Q, Vec3_t & v, double errTol=DBL_EPSILON) 00173 { 00174 Mat3_t A; 00175 Ten2Mat (TenA, A); 00176 return _jacobi_rot (/*N*/3, A, Q, v, errTol); 00177 } 00178 00179 #ifdef USE_BOOST_PYTHON 00180 inline int PyJacobiRot (BPy::list const & A, BPy::list & Q, BPy::list & V, double errTol=DBL_EPSILON) 00181 { 00182 Mat_t a, q; 00183 Vec_t v; 00184 List2Mat (A, a); 00185 int it = JacobiRot (a, q, v, errTol); 00186 Mat2List (q, Q); 00187 Vec2List (v, V); 00188 return it; 00189 } 00190 #endif 00191 00192 #endif // MECHSYS_LINALG_JACOBIROT_H