moab
|
00001 /* 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Coroporation, the U.S. Government 00007 * retains certain rights in this software. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 */ 00014 00023 #ifndef MOAB_MATRIX3_HPP 00024 #define MOAB_MATRIX3_HPP 00025 00026 #include "moab/Types.hpp" 00027 //#include "moab/EigenDecomp.hpp" 00028 #include <iostream> 00029 #include "moab/CartVect.hpp" 00030 00031 #include <iosfwd> 00032 #include <limits> 00033 #include <float.h> 00034 #include <assert.h> 00035 #ifdef _MSC_VER 00036 # define finite _finite 00037 #endif 00038 00039 namespace moab { 00040 00041 namespace Matrix{ 00042 template< typename Matrix> 00043 Matrix inverse( const Matrix & d, const double i){ 00044 Matrix m( d); 00045 m( 0) = i * (d(4) * d(8) - d(5) * d(7)); 00046 m( 1) = i * (d(2) * d(7) - d(8) * d(1)); 00047 m( 2) = i * (d(1) * d(5) - d(4) * d(2)); 00048 m( 3) = i * (d(5) * d(6) - d(8) * d(3)); 00049 m( 4) = i * (d(0) * d(8) - d(6) * d(2)); 00050 m( 5) = i * (d(2) * d(3) - d(5) * d(0)); 00051 m( 6) = i * (d(3) * d(7) - d(6) * d(4)); 00052 m( 7) = i * (d(1) * d(6) - d(7) * d(0)); 00053 m( 8) = i * (d(0) * d(4) - d(3) * d(1)); 00054 return m; 00055 } 00056 00057 template< typename Matrix> 00058 inline bool positive_definite( const Matrix & d, 00059 double& det ){ 00060 double subdet6 = d(1)*d(5)-d(2)*d(4); 00061 double subdet7 = d(2)*d(3)-d(0)*d(5); 00062 double subdet8 = d(0)*d(4)-d(1)*d(3); 00063 det = d(6)*subdet6 + d(7)*subdet7 + d(8)*subdet8; 00064 return d(0) > 0 && subdet8 > 0 && det > 0; 00065 } 00066 template< typename Matrix> 00067 inline Matrix transpose( const Matrix & d){ 00068 return Matrix( d(0), d(3), d(6), 00069 d(1), d(4), d(7), 00070 d(2), d(5), d(8) ); 00071 } 00072 template< typename Matrix> 00073 inline Matrix mmult3( const Matrix& a, const Matrix& b ) { 00074 return Matrix( a(0,0) * b(0,0) + a(0,1) * b(1,0) + a(0,2) * b(2,0), 00075 a(0,0) * b(0,1) + a(0,1) * b(1,1) + a(0,2) * b(2,1), 00076 a(0,0) * b(0,2) + a(0,1) * b(1,2) + a(0,2) * b(2,2), 00077 a(1,0) * b(0,0) + a(1,1) * b(1,0) + a(1,2) * b(2,0), 00078 a(1,0) * b(0,1) + a(1,1) * b(1,1) + a(1,2) * b(2,1), 00079 a(1,0) * b(0,2) + a(1,1) * b(1,2) + a(1,2) * b(2,2), 00080 a(2,0) * b(0,0) + a(2,1) * b(1,0) + a(2,2) * b(2,0), 00081 a(2,0) * b(0,1) + a(2,1) * b(1,1) + a(2,2) * b(2,1), 00082 a(2,0) * b(0,2) + a(2,1) * b(1,2) + a(2,2) * b(2,2) ); 00083 } 00084 00085 template< typename Vector, typename Matrix> 00086 inline Matrix outer_product( const Vector & u, 00087 const Vector & v, 00088 Matrix & m ) { 00089 m = Matrix( u[0] * v[0], u[0] * v[1], u[0] * v[2], 00090 u[1] * v[0], u[1] * v[1], u[1] * v[2], 00091 u[2] * v[0], u[2] * v[1], u[2] * v[2] ); 00092 return m; 00093 } 00094 template< typename Matrix> 00095 inline double determinant3( const Matrix & d){ 00096 return (d(0) * d(4) * d(8) 00097 + d(1) * d(5) * d(6) 00098 + d(2) * d(3) * d(7) 00099 - d(0) * d(5) * d(7) 00100 - d(1) * d(3) * d(8) 00101 - d(2) * d(4) * d(6)); 00102 } 00103 00104 template< typename Matrix> 00105 inline const Matrix inverse( const Matrix & d){ 00106 const double det = 1.0/determinant3( d); 00107 return inverse( d, det); 00108 } 00109 00110 template< typename Vector, typename Matrix> 00111 inline Vector vector_matrix( const Vector& v, const Matrix& m ) { 00112 return Vector( v[0] * m(0,0) + v[1] * m(1,0) + v[2] * m(2,0), 00113 v[0] * m(0,1) + v[1] * m(1,1) + v[2] * m(2,1), 00114 v[0] * m(0,2) + v[1] * m(1,2) + v[2] * m(2,2) ); 00115 } 00116 00117 template< typename Vector, typename Matrix> 00118 inline Vector matrix_vector( const Matrix& m, const Vector& v ){ 00119 Vector res = v; 00120 res[ 0] = v[0] * m(0,0) + v[1] * m(0,1) + v[2] * m(0,2); 00121 res[ 1] = v[0] * m(1,0) + v[1] * m(1,1) + v[2] * m(1,2); 00122 res[ 2] = v[0] * m(2,0) + v[1] * m(2,1) + v[2] * m(2,2); 00123 return res; 00124 } 00125 00126 // moved from EigenDecomp.hpp 00127 00128 // Jacobi iteration for the solution of eigenvectors/eigenvalues of a nxn 00129 // real symmetric matrix. Square nxn matrix a; size of matrix in n; 00130 // output eigenvalues in w; and output eigenvectors in v. Resulting 00131 // eigenvalues/vectors are sorted in decreasing order; eigenvectors are 00132 // normalized. 00133 // TODO: Remove this 00134 #define VTK_ROTATE(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);\ 00135 a[k][l]=h+s*(g-h*tau) 00136 00137 //TODO: Refactor this method into subroutines 00138 //use a namespace { } with no name to 00139 //contain subroutines so that the compiler 00140 //automatically inlines them. 00141 00142 template< typename Matrix, typename Vector> 00143 ErrorCode EigenDecomp( const Matrix & _a, 00144 double w[3], 00145 Vector v[3] ) { 00146 const int MAX_ROTATIONS = 20; 00147 const double one_ninth = 1./9; 00148 int i, j, k, iq, ip, numPos; 00149 double tresh, theta, tau, t, sm, s, h, g, c, tmp; 00150 double b[3], z[3]; 00151 Matrix a( _a); 00152 00153 // initialize 00154 for (ip=0; ip<3; ip++) { 00155 for (iq=0; iq<3; iq++){ 00156 v[ip][iq] = 0.0; 00157 } 00158 v[ip][ip] = 1.0; 00159 } 00160 for (ip=0; ip<3; ip++) { 00161 b[ip] = w[ip] = a[ip][ip]; 00162 z[ip] = 0.0; 00163 } 00164 00165 // begin rotation sequence 00166 for (i=0; i<MAX_ROTATIONS; i++){ 00167 sm = 0.0; 00168 for (ip=0; ip<2; ip++){ 00169 for (iq=ip+1; iq<3; iq++){ sm += fabs(a[ip][iq]); } 00170 } 00171 00172 if ( sm == 0.0 ){ break; } 00173 // first 3 sweeps 00174 tresh = (i < 3)? 0.2*sm*one_ninth : 0.0; 00175 for (ip=0; ip<2; ip++) { 00176 for (iq=ip+1; iq<3; iq++) { 00177 g = 100.0*fabs(a[ip][iq]); 00178 00179 // after 4 sweeps 00180 if ( i > 3 && (fabs(w[ip])+g) == fabs(w[ip]) 00181 && (fabs(w[iq])+g) == fabs(w[iq])) { 00182 a[ip][iq] = 0.0; 00183 } 00184 else if ( fabs(a[ip][iq]) > tresh) { 00185 h = w[iq] - w[ip]; 00186 if ( (fabs(h)+g) == fabs(h)){ t = (a[ip][iq]) / h; } 00187 else { 00188 theta = 0.5*h / (a[ip][iq]); 00189 t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta)); 00190 if (theta < 0.0) { t = -t;} 00191 } 00192 c = 1.0 / sqrt(1+t*t); 00193 s = t*c; 00194 tau = s/(1.0+c); 00195 h = t*a[ip][iq]; 00196 z[ip] -= h; 00197 z[iq] += h; 00198 w[ip] -= h; 00199 w[iq] += h; 00200 a[ip][iq]=0.0; 00201 // ip already shifted left by 1 unit 00202 for (j = 0;j <= ip-1;j++) { VTK_ROTATE(a,j,ip,j,iq); } 00203 // ip and iq already shifted left by 1 unit 00204 for (j = ip+1;j <= iq-1;j++) { VTK_ROTATE(a,ip,j,j,iq); } 00205 // iq already shifted left by 1 unit 00206 for (j=iq+1; j<3; j++) { VTK_ROTATE(a,ip,j,iq,j); } 00207 for (j=0; j<3; j++) { VTK_ROTATE(v,j,ip,j,iq); } 00208 } 00209 } 00210 } 00211 00212 for (ip=0; ip<3; ip++) { 00213 b[ip] += z[ip]; 00214 w[ip] = b[ip]; 00215 z[ip] = 0.0; 00216 } 00217 } 00218 00220 if ( i >= MAX_ROTATIONS ) { 00221 std::cerr << "Matrix3D: Error extracting eigenfunctions" << std::endl; 00222 return MB_FAILURE; 00223 } 00224 00225 // sort eigenfunctions these changes do not affect accuracy 00226 for (j=0; j<2; j++){ // boundary incorrect 00227 k = j; 00228 tmp = w[k]; 00229 for (i=j+1; i<3; i++){ // boundary incorrect, shifted already 00230 if (w[i] >= tmp){ // why exchage if same? 00231 k = i; 00232 tmp = w[k]; 00233 } 00234 } 00235 if (k != j){ 00236 w[k] = w[j]; 00237 w[j] = tmp; 00238 for (i=0; i<3; i++){ 00239 tmp = v[i][j]; 00240 v[i][j] = v[i][k]; 00241 v[i][k] = tmp; 00242 } 00243 } 00244 } 00245 // insure eigenvector consistency (i.e., Jacobi can compute vectors that 00246 // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can 00247 // reek havoc in hyperstreamline/other stuff. We will select the most 00248 // positive eigenvector. 00249 int ceil_half_n = (3 >> 1) + (3 & 1); 00250 for (j=0; j<3; j++) { 00251 for (numPos=0, i=0; i<3; i++) { 00252 if ( v[i][j] >= 0.0 ) { numPos++; } 00253 } 00254 // if ( numPos < ceil(double(n)/double(2.0)) ) 00255 if ( numPos < ceil_half_n) { 00256 for(i=0; i<3; i++) { v[i][j] *= -1.0; } 00257 } 00258 } 00259 return MB_SUCCESS; 00260 } 00261 } //namespace Matrix 00262 00263 class Matrix3 { 00264 //TODO: std::array when we can use C++11 00265 double d[9]; 00266 00267 public: 00268 //Default Constructor 00269 inline Matrix3(){ 00270 for(int i = 0; i < 9; ++i){ d[ i] = 0; } 00271 } 00272 //TODO: Deprecate this. 00273 //Then we can go from three Constructors to one. 00274 inline Matrix3( double diagonal ){ 00275 d[0] = d[4] = d[8] = diagonal; 00276 d[1] = d[2] = d[3] = 0.0; 00277 d[5] = d[6] = d[7] = 0.0; 00278 } 00279 inline Matrix3( const CartVect & diagonal ){ 00280 d[0] = diagonal[0]; 00281 d[4] = diagonal[1], 00282 d[8] = diagonal[2]; 00283 d[1] = d[2] = d[3] = 0.0; 00284 d[5] = d[6] = d[7] = 0.0; 00285 } 00286 //TODO: not strictly correct as the Matrix3 object 00287 //is a double d[ 9] so the only valid model of T is 00288 //double, or any refinement (int, float) 00289 //*but* it doesn't really matter anything else 00290 //will fail to compile. 00291 template< typename T> 00292 inline Matrix3( const std::vector< T> & diagonal ){ 00293 d[0] = diagonal[0]; 00294 d[4] = diagonal[1], 00295 d[8] = diagonal[2]; 00296 d[1] = d[2] = d[3] = 0.0; 00297 d[5] = d[6] = d[7] = 0.0; 00298 } 00299 00300 inline Matrix3( double v00, double v01, double v02, 00301 double v10, double v11, double v12, 00302 double v20, double v21, double v22 ){ 00303 d[0] = v00; d[1] = v01; d[2] = v02; 00304 d[3] = v10; d[4] = v11; d[5] = v12; 00305 d[6] = v20; d[7] = v21; d[8] = v22; 00306 } 00307 00308 //Copy constructor 00309 Matrix3 ( const Matrix3 & f){ 00310 for(int i = 0; i < 9; ++i) { d[ i] = f.d[ i]; } 00311 } 00312 //Weird constructors 00313 template< typename Vector> 00314 inline Matrix3( const Vector & row0, 00315 const Vector & row1, 00316 const Vector & row2 ) { 00317 for(std::size_t i = 0; i < 3; ++i){ 00318 d[ i] = row0[ i]; 00319 d[ i+3]= row1[ i]; 00320 d[ i+6] = row2[ i]; 00321 } 00322 } 00323 00324 inline Matrix3( const double* v ){ 00325 d[0] = v[0]; d[1] = v[1]; d[2] = v[2]; 00326 d[3] = v[3]; d[4] = v[4]; d[5] = v[5]; 00327 d[6] = v[6]; d[7] = v[7]; d[8] = v[8]; 00328 } 00329 00330 inline Matrix3& operator=( const Matrix3& m ){ 00331 d[0] = m.d[0]; d[1] = m.d[1]; d[2] = m.d[2]; 00332 d[3] = m.d[3]; d[4] = m.d[4]; d[5] = m.d[5]; 00333 d[6] = m.d[6]; d[7] = m.d[7]; d[8] = m.d[8]; 00334 return *this; 00335 } 00336 00337 inline Matrix3& operator=( const double* v ){ 00338 d[0] = v[0]; d[1] = v[1]; d[2] = v[2]; 00339 d[3] = v[3]; d[4] = v[4]; d[5] = v[5]; 00340 d[6] = v[6]; d[7] = v[7]; d[8] = v[8]; 00341 return *this; 00342 } 00343 00344 inline double* operator[]( unsigned i ){ return d + 3*i; } 00345 inline const double* operator[]( unsigned i ) const{ return d + 3*i; } 00346 inline double& operator()(unsigned r, unsigned c) { return d[3*r+c]; } 00347 inline double operator()(unsigned r, unsigned c) const { return d[3*r+c]; } 00348 inline double& operator()(unsigned i) { return d[i]; } 00349 inline double operator()(unsigned i) const { return d[i]; } 00350 00351 // get pointer to array of nine doubles 00352 inline double* array() 00353 { return d; } 00354 inline const double* array() const 00355 { return d; } 00356 00357 inline Matrix3& operator+=( const Matrix3& m ){ 00358 d[0] += m.d[0]; d[1] += m.d[1]; d[2] += m.d[2]; 00359 d[3] += m.d[3]; d[4] += m.d[4]; d[5] += m.d[5]; 00360 d[6] += m.d[6]; d[7] += m.d[7]; d[8] += m.d[8]; 00361 return *this; 00362 } 00363 00364 inline Matrix3& operator-=( const Matrix3& m ){ 00365 d[0] -= m.d[0]; d[1] -= m.d[1]; d[2] -= m.d[2]; 00366 d[3] -= m.d[3]; d[4] -= m.d[4]; d[5] -= m.d[5]; 00367 d[6] -= m.d[6]; d[7] -= m.d[7]; d[8] -= m.d[8]; 00368 return *this; 00369 } 00370 00371 inline Matrix3& operator*=( double s ){ 00372 d[0] *= s; d[1] *= s; d[2] *= s; 00373 d[3] *= s; d[4] *= s; d[5] *= s; 00374 d[6] *= s; d[7] *= s; d[8] *= s; 00375 return *this; 00376 } 00377 00378 inline Matrix3& operator/=( double s ){ 00379 d[0] /= s; d[1] /= s; d[2] /= s; 00380 d[3] /= s; d[4] /= s; d[5] /= s; 00381 d[6] /= s; d[7] /= s; d[8] /= s; 00382 return *this; 00383 } 00384 00385 inline Matrix3& operator*=( const Matrix3& m ){ 00386 (*this) = moab::Matrix::mmult3((*this),m); 00387 return *this; 00388 } 00389 00390 inline double determinant() const{ 00391 return moab::Matrix::determinant3( *this); 00392 } 00393 00394 inline Matrix3 inverse() const { 00395 const double i = 1.0/determinant(); 00396 return moab::Matrix::inverse( *this, i); 00397 } 00398 inline Matrix3 inverse( double i ) const { 00399 return moab::Matrix::inverse( *this, i); 00400 } 00401 00402 inline bool positive_definite() const{ 00403 double tmp; 00404 return positive_definite( tmp); 00405 } 00406 00407 inline bool positive_definite( double& det ) const{ 00408 return moab::Matrix::positive_definite( *this, det); 00409 } 00410 00411 inline Matrix3 transpose() const{ return moab::Matrix::transpose( *this); } 00412 00413 inline bool invert() { 00414 double i = 1.0 / determinant(); 00415 if (!finite(i) || fabs(i) < std::numeric_limits<double>::epsilon()) 00416 return false; 00417 *this = inverse( i ); 00418 return true; 00419 } 00420 // Calculate determinant of 2x2 submatrix composed of the 00421 // elements not in the passed row or column. 00422 inline double subdet( int r, int c ) const{ 00423 const int r1 = (r+1)%3, r2 = (r+2)%3; 00424 const int c1 = (c+1)%3, c2 = (c+2)%3; 00425 assert(r >= 0 && c >= 0); 00426 if (r < 0 || c < 0) return DBL_MAX; 00427 return d[3*r1+c1]*d[3*r2+c2] - d[3*r1+c2]*d[3*r2+c1]; 00428 } 00429 }; //class Matrix3 00430 00431 inline Matrix3 operator+( const Matrix3& a, const Matrix3& b ){ 00432 return Matrix3(a) += b; 00433 } 00434 inline Matrix3 operator-( const Matrix3& a, const Matrix3& b ){ 00435 return Matrix3(a) -= b; 00436 } 00437 00438 inline Matrix3 operator*( const Matrix3& a, const Matrix3& b ) { 00439 return moab::Matrix::mmult3( a, b); 00440 } 00441 00442 template< typename Vector> 00443 inline Matrix3 outer_product( const Vector & u, 00444 const Vector & v ) { 00445 return Matrix3( u[0] * v[0], u[0] * v[1], u[0] * v[2], 00446 u[1] * v[0], u[1] * v[1], u[1] * v[2], 00447 u[2] * v[0], u[2] * v[1], u[2] * v[2] ); 00448 } 00449 00450 template< typename T> 00451 inline std::vector< T> operator*( const Matrix3&m, const std::vector< T> & v){ 00452 return moab::Matrix::matrix_vector( m, v); 00453 } 00454 00455 template< typename T> 00456 inline std::vector< T> operator*( const std::vector< T>& v, const Matrix3&m){ 00457 return moab::Matrix::vector_matrix( v, m); 00458 } 00459 00460 inline CartVect operator*( const Matrix3&m, const CartVect& v){ 00461 return moab::Matrix::matrix_vector( m, v); 00462 } 00463 00464 inline CartVect operator*( const CartVect& v, const Matrix3& m){ 00465 return moab::Matrix::vector_matrix( v, m); 00466 } 00467 00468 } // namespace moab 00469 00470 #ifndef MOAB_MATRIX3_OPERATORLESS 00471 #define MOAB_MATRIX3_OPERATORLESS 00472 inline std::ostream& operator<<( std::ostream& s, const moab::Matrix3& m ){ 00473 return s << "| " << m(0,0) << " " << m(0,1) << " " << m(0,2) 00474 << " | " << m(1,0) << " " << m(1,1) << " " << m(1,2) 00475 << " | " << m(2,0) << " " << m(2,1) << " " << m(2,2) 00476 << " |" ; 00477 } 00478 #endif//MOAB_MATRIX3_OPERATORLESS 00479 #endif //MOAB_MATRIX3_HPP