MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/linalg/matvec.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand                   *
00004  * Copyright (C) 2009 Sergio Galindo                                    *
00005  *                                                                      *
00006  * This program is free software: you can redistribute it and/or modify *
00007  * it under the terms of the GNU General Public License as published by *
00008  * the Free Software Foundation, either version 3 of the License, or    *
00009  * any later version.                                                   *
00010  *                                                                      *
00011  * This program is distributed in the hope that it will be useful,      *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00014  * GNU General Public License for more details.                         *
00015  *                                                                      *
00016  * You should have received a copy of the GNU General Public License    *
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00018  ************************************************************************/
00019 
00020 #ifndef MECHSYS_MATVEC_H
00021 #define MECHSYS_MATVEC_H
00022 
00023 // Std Lib
00024 #include <iostream>
00025 #include <sstream>   // for istringstream, ostringstream
00026 #include <cstring>   // for strcmp
00027 #include <cmath>     // for sqrt, pow
00028 #include <algorithm> // for min, max
00029 
00030 // Blitz++
00031 #include <blitz/tinyvec-et.h>
00032 #include <blitz/tinymat.h>
00033 
00034 // GSL
00035 #include <gsl/gsl_math.h>
00036 #include <gsl/gsl_eigen.h>
00037 
00038 // Tensors
00039 #ifdef HAS_TENSORS
00040   #include <tensors/tensoperators.h>
00041   #include <tensors/tensor1.h>
00042   #include <tensors/tensor2.h>
00043   #include <tensors/tensor3.h>
00044   #include <tensors/tensor4.h>
00045   typedef TensorsLib::Tensor1<double,3> Ten1_t;
00046   typedef TensorsLib::Tensor2<double,3> Ten2_t;
00047   typedef TensorsLib::Tensor3<double,3> Ten3_t;
00048   typedef TensorsLib::Tensor4<double,3> Ten4_t;
00049 #endif
00050 
00051 // MechSys
00052 #include <mechsys/util/fatal.h>
00053 #include <mechsys/util/util.h>
00054 #include <mechsys/util/array.h>
00055 
00056 // LAPACK
00057 extern "C"
00058 {
00059     // DGETRF - compute an LU factorization of a general M-by-N matrix A using partial pivoting with row interchanges
00060     void dgetrf_(const int* m, const int* n, double* a, const int* lda, int* ipiv, int* info);
00061 
00062     // DGETRI - compute the inverse of a matrix using the LU factorization computed by DGETRF
00063     void dgetri_(const int* n, double* a, const int* lda, int* ipiv, double* work, const int* lwork, int* info);
00064 
00065     // DGESVD - computes the singular value decomposition of a real M-by-N matrix A, optionally computing the left and/or right singular vectors
00066     void dgesvd_(const char* jobu, const char* jobvt, const int* M, const int* N, double* A, const int* lda, double* S, double* U, const int* ldu, double* VT, const int* ldvt, double* work,const int* lwork, const int* info);
00067 
00068     // DGESV - double-general-solver
00069     void dgesv_(int *Np, int *NRHSp, double *A, int *LDAp, int *IPIVp, double *B, int *LDBp, int *INFOp);
00070 }
00071 
00072 
00074 
00075 
00076 #ifdef USE_MTL4
00077 
00078 // Boost/MTL4
00079 #include <boost/numeric/mtl/mtl.hpp>
00080 
00082 typedef mtl::dense2D<double, mtl::matrix::parameters<mtl::tag::col_major> > Mat_t;
00083 
00085 typedef mtl::dense_vector<double> Vec_t;
00086 
00087 #else
00088 
00089 #include <mechsys/linalg/vector.h>
00090 #include <mechsys/linalg/matrix.h>
00091 #include <mechsys/linalg/laexpr.h>
00092 
00093 typedef LinAlg::Vector<double> Vec_t;
00094 typedef LinAlg::Matrix<double> Mat_t;
00095 
00096 inline double dot         (Vec_t const & V, Vec_t const & W) { return LinAlg::Dot(V,W); }
00097 inline size_t size        (Vec_t const & V) { return V.Size(); }
00098 inline void   set_to_zero (Vec_t       & V) { V.SetValues(0.0); }
00099 inline void   set_to_zero (Mat_t       & M) { M.SetValues(0.0); }
00100 inline size_t num_rows    (Vec_t const & V) { return V.Size(); }
00101 inline size_t num_rows    (Mat_t const & M) { return M.Rows(); }
00102 inline size_t num_cols    (Mat_t const & M) { return M.Cols(); }
00103 
00104 #endif
00105 
00107 inline String PrintVector (Vec_t const & V, char const * Fmt="%13g", Array<long> const * SkipR=NULL, double Tol=1.0e-13)
00108 {
00109     int m = size(V);
00110     String lin;
00111     for (int i=0; i<m; ++i)
00112     {
00113         bool skip_row = false;
00114         if (SkipR!=NULL) skip_row = (SkipR->Find(i)<0 ? false : true);
00115         if (!skip_row)
00116         {
00117             double val = (fabs(V(i))<Tol ? 0.0 : V(i));
00118             String buf;  buf.Printf(Fmt,val);
00119             lin.append(buf);
00120         }
00121     }
00122     lin.append("\n");
00123     return lin;
00124 }
00125 
00127 inline String PrintMatrix (Mat_t const & M, char const * Fmt="%13g", Array<long> const * SkipRC=NULL, double Tol=1.0e-13, bool NumPy=false)
00128 {
00129     int m = M.num_rows();
00130     int n = M.num_cols();
00131     String lin;
00132     if (NumPy) lin.append("matrix([[");
00133     for (int i=0; i<m; ++i)
00134     {
00135         bool skip_row = false;
00136         if (SkipRC!=NULL) skip_row = (SkipRC->Find(i)<0 ? false : true);
00137         if (!skip_row)
00138         {
00139             if (NumPy && i!=0) lin.append("        [");
00140             for (int j=0; j<n; ++j)
00141             {
00142                 bool skip_col = false;
00143                 if (SkipRC!=NULL) skip_col = (SkipRC->Find(j)<0 ? false : true);
00144                 if (!skip_col)
00145                 {
00146                     double val = (fabs(M(i,j))<Tol ? 0.0 : M(i,j));
00147                     String buf;  buf.Printf(Fmt,val);
00148                     lin.append(buf);
00149                     if (NumPy && j!=n-1) lin.append(",");
00150                 }
00151             }
00152             if (NumPy && i!=m-1) lin.append("],");
00153             if (NumPy && i==m-1) lin.append("]])");
00154             else lin.append("\n");
00155         }
00156     }
00157     return lin;
00158 }
00159 
00161 inline void WriteSMAT (Mat_t const & M, char const * FileKey, double Tol=1.0e-14)
00162 {
00163     // find the number of really non-zero values
00164     size_t m  = num_rows(M);
00165     size_t n  = num_cols(M);
00166     size_t nz = 0;
00167     for (size_t i=0; i<m; ++i)
00168     for (size_t j=0; j<n; ++j)
00169     {
00170         if (fabs(M(i,j))>Tol) nz++;
00171     }
00172 
00173     // output
00174     std::ostringstream oss;
00175     char buf[256];
00176     sprintf(buf, "%zd  %zd  %zd\n", m, n, nz);
00177     oss << buf;
00178     for (size_t i=0; i<m; ++i)
00179     for (size_t j=0; j<n; ++j)
00180     {
00181         if (fabs(M(i,j))>Tol)
00182         {
00183             sprintf(buf, "  %zd  %zd  %.17g\n", i, j, M(i,j));
00184             oss << buf;
00185         }
00186     }
00187 
00188     // write to file
00189     String fn(FileKey);  fn.append(".smat");
00190     std::ofstream of(fn.CStr(), std::ios::out);
00191     of << oss.str();
00192     of.close();
00193     printf("File <%s%s%s> written\n",TERM_CLR_BLUE_H, fn.CStr(), TERM_RST);
00194 }
00195 
00197 inline double CompareVectors (Vec_t const & A, Vec_t const & B)
00198 {
00199     size_t m = size(A);
00200     if (m!=size(B)) throw new Fatal("matvec.h:CompareVectors: vectors A_%d and B_%d must have the same size",m,size(B));
00201     double error = 0.0;
00202     for (size_t i=0; i<m; ++i)
00203         error += fabs(A(i)-B(i));
00204     return error;
00205 }
00206 
00208 inline double CompareMatrices (Mat_t const & A, Mat_t const & B)
00209 {
00210     size_t m = A.num_rows();
00211     size_t n = A.num_cols();
00212     if ((m!=B.num_rows()) || (n!=B.num_cols())) throw new Fatal("matvec.h:CompareMatrices: matrices A_%dx%d and B_%dx%d must have the same number of rows and columns",m,n,B.num_rows(),B.num_cols());
00213     double error = 0.0;
00214     for (size_t i=0; i<m; ++i)
00215     for (size_t j=0; j<n; ++j)
00216         error += fabs(A(i,j)-B(i,j));
00217     return error;
00218 }
00219 
00221 inline double CheckDiagonal (Mat_t const & M, bool CheckUnitDiag=false)
00222 {
00223     size_t m = M.num_rows();
00224     size_t n = M.num_cols();
00225     double error = 0.0;
00226     for (size_t i=0; i<m; ++i)
00227     for (size_t j=0; j<n; ++j)
00228     {
00229         if ((i==j) && CheckUnitDiag) error += fabs(M(i,j)-1.0);
00230         if  (i!=j)                   error += fabs(M(i,j));
00231     }
00232     return error;
00233 }
00234 
00236 inline double Det (Mat_t const & M)
00237 {
00238     int m = M.num_rows();
00239     int n = M.num_cols();
00240     if (m==1)
00241     {
00242         double res = 0;
00243         for (int i=0; i<n; i++) res += M(0,i)*M(0,i);
00244         return sqrt(res);
00245     }
00246     else if (m==2 && n==2)
00247     {
00248         return M(0,0)*M(1,1) - M(1,0)*M(0,1);
00249     }
00250     /*
00251     else if (m==2 && n==3)
00252     {
00253         double d1 = M(0,0)*M(1,1) - M(0,1)*M(1,0);
00254         double d2 = M(0,1)*M(1,2) - M(0,2)*M(1,1);
00255         double d3 = M(0,2)*M(1,0) - M(0,0)*M(1,2);
00256         return sqrt(d1*d1 + d2*d2 + d3*d3);
00257     }
00258     */
00259     else if (m==3 && n==3)
00260     {
00261         return  M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1))
00262               - M(0,1)*(M(1,0)*M(2,2) - M(1,2)*M(2,0))
00263               + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
00264     }
00265     else if (m==n)
00266     {
00267         // factorization
00268         int   info = 0;
00269         int * ipiv = new int [m];
00270         Mat_t Mcpy(M);
00271         dgetrf_(&m,         // M
00272                 &m,         // N
00273                 Mcpy.data,  // double * A
00274                 &m,         // LDA
00275                 ipiv,       // Pivot indices
00276                 &info);     // INFO
00277         if (info!=0) throw new Fatal ("matvec.h::Det: LAPACK: LU factorization failed");
00278 
00279         // determinant
00280         double det = 1.0;
00281         for (int i=0; i<m; ++i)
00282         {
00283             if (ipiv[i]!=(i+1)) det = -det * Mcpy(i,i);
00284             else                det =  det * Mcpy(i,i);
00285         }
00286 
00287         // end
00288         delete [] ipiv;
00289         return det;
00290     }
00291     else throw new Fatal("matvec.h:Det: Method is not implemented for (%d x %d) matrices yet",m,n);
00292 }
00293 
00295 inline void Identity (size_t NRows, Mat_t & I)
00296 {
00297     I.change_dim (NRows,NRows);
00298     for (size_t i=0; i<NRows; ++i)
00299     for (size_t j=0; j<NRows; ++j)
00300     {
00301         if (i==j) I(i,j) = 1.0;
00302         else      I(i,j) = 0.0;
00303     }
00304 }
00305 
00307 inline void Svd (Mat_t const & M, Mat_t & U, Vec_t & S, Mat_t & Vt)
00308 {
00309     int  info   = 0;
00310     char job    = 'A';
00311     int  m      = M.num_rows();
00312     int  n      = M.num_cols();
00313     int  min_mn = (m<n ? m : n);
00314     int  max_mn = (m>n ? m : n);
00315     int  lwork  = 2.0*std::max(3*min_mn+max_mn, 5*min_mn);
00316 
00317     U. change_dim (m, m);
00318     Vt.change_dim (n, n); // trans(V)
00319     S. change_dim (min_mn);
00320 
00321     double * work  = new double [lwork]; // Work
00322 
00323     // decomposition
00324     Mat_t tmp(M);
00325     dgesvd_(&job,      // JOBU
00326             &job,      // JOBVT
00327             &m,        // M
00328             &n,        // N
00329             tmp.data,  // A
00330             &m,        // LDA
00331             S.data,    // S
00332             U.data,    // U
00333             &m,        // LDU
00334             Vt.data,   // VT
00335             &n,        // LDVT
00336             work,      // WORK
00337             &lwork,    // LWORK
00338             &info);    // INFO
00339     if (info!=0) throw new Fatal ("matvec::Svd: LAPACK: Decomposition failed");
00340 
00341     delete [] work;
00342 }
00343 
00345 inline void Inv (Mat_t const & M, Mat_t & Mi, double Tol=1.0e-10)
00346 {
00347     int m = M.num_rows();
00348     int n = M.num_cols();
00349     Mi.change_dim(m,n);
00350     if (m==2 && n==2)
00351     {
00352         double det = Det(M);
00353         if (fabs(det)<Tol) throw new Fatal("matvec.h:Inv: Cannot calculate inverse due to zero determinant. det = %g",det);
00354 
00355         Mi(0,0) =  M(1,1) / det;
00356         Mi(0,1) = -M(0,1) / det;
00357 
00358         Mi(1,0) = -M(1,0) / det;
00359         Mi(1,1) =  M(0,0) / det;
00360     }
00361     else if (m==3 && n==3)
00362     {
00363         double det = Det(M);
00364         if (fabs(det)<Tol) throw new Fatal("matvec.h:Inv: Cannot calculate inverse due to zero determinant. det = %g",det);
00365 
00366         Mi(0,0) = (M(1,1)*M(2,2) - M(1,2)*M(2,1)) / det;
00367         Mi(0,1) = (M(0,2)*M(2,1) - M(0,1)*M(2,2)) / det;
00368         Mi(0,2) = (M(0,1)*M(1,2) - M(0,2)*M(1,1)) / det;
00369 
00370         Mi(1,0) = (M(1,2)*M(2,0) - M(1,0)*M(2,2)) / det;
00371         Mi(1,1) = (M(0,0)*M(2,2) - M(0,2)*M(2,0)) / det;
00372         Mi(1,2) = (M(0,2)*M(1,0) - M(0,0)*M(1,2)) / det;
00373 
00374         Mi(2,0) = (M(1,0)*M(2,1) - M(1,1)*M(2,0)) / det;
00375         Mi(2,1) = (M(0,1)*M(2,0) - M(0,0)*M(2,1)) / det;
00376         Mi(2,2) = (M(0,0)*M(1,1) - M(0,1)*M(1,0)) / det;
00377     }
00378     else if (m==n) // square
00379     {
00380         int   info = 0;
00381         int * ipiv = new int [m];
00382 
00383         // factorization
00384         Mi = M;
00385         dgetrf_(&m,       // M
00386                 &m,       // N
00387                 Mi.data,  // double * A
00388                 &m,       // LDA
00389                 ipiv,     // Pivot indices
00390                 &info);   // INFO
00391         if (info!=0) throw new Fatal ("matvec.h::Inv: LAPACK: LU factorization failed");
00392 
00393         int      NB    = 4;                  // Optimal blocksize ?
00394         int      lwork = m*NB;               // Dimension of work >= max(1,m), optimal=m*NB
00395         double * work  = new double [lwork]; // Work
00396 
00397         // inversion
00398         dgetri_(&m,       // N
00399                 Mi.data,  // double * A
00400                 &m,       // LDA
00401                 ipiv,     // Pivot indices
00402                 work,     // work
00403                 &lwork,   // dimension of work
00404                 &info);   // INFO
00405         if (info!=0) throw new Fatal ("matvec::Inv: LAPACK: Inversion failed");
00406 
00407         delete [] ipiv;
00408         delete [] work;
00409     }
00410     else // generalized (pseudo) inverse
00411     {
00412         Mat_t U; Vec_t S; Mat_t Vt;
00413         Svd(M, U, S, Vt);
00414         Mat_t Di(m,n);
00415         set_to_zero(Di);
00416         for (size_t i=0; i<size(S); ++i)
00417         {
00418             if (S(i)>Tol) Di(i,i) = 1.0/S(i);
00419         }
00420         Mat_t tmp(U*Di*Vt);
00421         Mi.change_dim(n,m);
00422         Mi = trans(tmp);
00423     }
00424 }
00425 
00427 inline void Sol (Mat_t & M, Vec_t & X)
00428 {
00429     int  m = M.num_rows();
00430     int  n = M.num_cols();
00431     int mv = size(X);
00432     if (m!=n)  throw new Fatal("Sol: Matrix must be square");
00433     if (m!=mv) throw new Fatal("Sol: Vector X must have the same number of rows of matrix M");
00434 
00435     int   info = 0;
00436     int   nrhs = 1; // vector X has 1 column
00437     int * ipiv = new int [m];
00438     dgesv_(&m,      // A(m,m)
00439            &nrhs,   // {X}(m,1) (RHS: Right Hand Side) 
00440            M.data,  // double * A
00441            &m,      // LDA
00442            ipiv,    // Pivot Indices
00443            X.data,  // double * Y
00444            &m,      // LDY
00445            &info);  // info
00446     delete [] ipiv;
00447 
00448     if (info!=0) 
00449     {
00450         throw new Fatal ("Sol: Linear solver (DGESV) failed (singular matrix?)");
00451     }
00452 }
00453 
00455 inline void Sol (Mat_t const & M, Vec_t const & B, Vec_t & X)
00456 {
00457     Mat_t m(M);
00458     X = B;
00459     Sol (m, X);
00460 }
00461 
00463 inline double Norm (Vec_t const & V)
00464 {
00465     return sqrt(dot(V,V));
00466 }
00467 
00469 inline void Dyad (Vec_t const & A, Vec_t const & B, Mat_t & M)
00470 {
00471     M.change_dim(size(A),size(B));
00472     for (size_t i=0; i<size(A); ++i)
00473     for (size_t j=0; j<size(B); ++j)
00474         M(i,j) = A(i) * B(j);
00475 }
00476 
00478 inline void Mult (Vec_t const & A, Mat_t const & M, Vec_t & B)
00479 {
00480     B.change_dim (M.num_cols());
00481     set_to_zero  (B);
00482     for (size_t i=0; i<M.num_rows(); ++i)
00483     for (size_t j=0; j<M.num_cols(); ++j)
00484         B(j) += A(i)*M(i,j);
00485 }
00486 
00488 inline void Vec2ColMat (Vec_t const & V, Mat_t & M)
00489 {
00490     M.change_dim (size(V),1);
00491     for (size_t i=0; i<size(V); ++i) M(i,0) = V(i);
00492 }
00493 
00495 inline void Eig (Mat_t & M, Vec_t & L, Mat_t * Q=NULL, bool Qtrans=false)
00496 {
00497     // calculate
00498     size_t nrow = num_rows (M);
00499     size_t ncol = num_cols (M);
00500     if (nrow!=ncol) throw new Fatal("Eig: Matrix (%zdx%zd) must be square", nrow,ncol);
00501 
00502     // eigenvalues
00503     L.change_dim (nrow);
00504     gsl_vector eval = {nrow, 1, L.data, NULL, 0}; // size, stride, data, block, owner
00505 
00506     // solve
00507     gsl_matrix_view m = gsl_matrix_view_array (M.data, nrow, nrow);
00508     if (Q==NULL)
00509     {
00510         gsl_eigen_symm_workspace * w = gsl_eigen_symm_alloc (nrow);
00511         gsl_eigen_symm (&m.matrix, &eval, w);
00512         gsl_eigen_symm_free (w);
00513     }
00514     else
00515     {
00516         Q->change_dim (nrow, nrow);
00517         gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc (nrow);
00518         if (Qtrans)
00519         {
00520             gsl_matrix_view q = gsl_matrix_view_array (Q->data, nrow, nrow);
00521             gsl_eigen_symmv (&m.matrix, &eval, &q.matrix, w);
00522         }
00523         else
00524         {
00525             gsl_matrix * q = gsl_matrix_alloc (nrow, nrow);
00526             gsl_eigen_symmv (&m.matrix, &eval, q, w);
00527             for (size_t j=0; j<ncol; ++j)
00528             {
00529                 gsl_vector_view evec_j = gsl_matrix_column (q, j);
00530                 for (size_t i=0; i<nrow; ++i) (*Q)(i,j) = gsl_vector_get (&evec_j.vector, i);
00531             }
00532             gsl_matrix_free (q);
00533         }
00534         gsl_eigen_symmv_free (w);
00535     }
00536 }
00537 
00538 
00540 
00541 
00543 typedef blitz::TinyMatrix<double,3,3> Mat3_t;
00544 
00546 typedef blitz::TinyVector<double,3> Vec3_t;
00547 typedef blitz::TinyVector<size_t,3> iVec3_t;
00548 typedef blitz::TinyVector<bool,3>   bVec3_t;
00549 
00551 inline String PrintVector (Vec3_t const & V, char const * Fmt="%13g", double Tol=1.0e-13)
00552 {
00553     int m = 3;
00554     String lin;
00555     for (int i=0; i<m; ++i)
00556     {
00557         double val = (fabs(V(i))<Tol ? 0.0 : V(i));
00558         String buf;  buf.Printf(Fmt,val);
00559         lin.append(buf);
00560     }
00561     lin.append("\n");
00562     return lin;
00563 }
00564 
00566 inline String PrintMatrix (Mat3_t const & M, char const * Fmt="%13g", double Tol=1.0e-13)
00567 {
00568     int m = 3;
00569     int n = 3;
00570     String lin;
00571     for (int i=0; i<m; ++i)
00572     {
00573         for (int j=0; j<n; ++j)
00574         {
00575             double val = (fabs(M(i,j))<Tol ? 0.0 : M(i,j));
00576             String buf;  buf.Printf(Fmt,val);
00577             lin.append(buf);
00578         }
00579         lin.append("\n");
00580     }
00581     return lin;
00582 }
00583 
00585 inline double CompareVectors (Vec3_t const & A, Vec3_t const & B)
00586 {
00587     double error = 0.0;
00588     for (size_t i=0; i<3; ++i)
00589         error += fabs(A(i)-B(i));
00590     return error;
00591 }
00592 
00594 inline double CompareMatrices (Mat3_t const & A, Mat3_t const & B)
00595 {
00596     double error = 0.0;
00597     for (size_t i=0; i<3; ++i)
00598     for (size_t j=0; j<3; ++j)
00599         error += fabs(A(i,j)-B(i,j));
00600     return error;
00601 }
00602 
00604 inline void Trans (Mat3_t const & M, Mat3_t & Mt)
00605 {
00606     Mt(0,0)=M(0,0);   Mt(0,1)=M(1,0);   Mt(0,2)=M(2,0);
00607     Mt(1,0)=M(0,1);   Mt(1,1)=M(1,1);   Mt(1,2)=M(2,1);
00608     Mt(2,0)=M(0,2);   Mt(2,1)=M(1,2);   Mt(2,2)=M(2,2);
00609 }
00610 
00612 inline double Det (Mat3_t const & M)
00613 {
00614     double det =   M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1))
00615                  - M(0,1)*(M(1,0)*M(2,2) - M(1,2)*M(2,0))
00616                  + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
00617     return det;
00618 }
00619 
00621 inline void Identity (Mat3_t & I)
00622 {
00623     I = 1.0, 0.0, 0.0,
00624         0.0, 1.0, 0.0,
00625         0.0, 0.0, 1.0;
00626 }
00627 
00629 inline void Inv (Mat3_t const & M, Mat3_t & Mi, double Tol=1.0e-10)
00630 {
00631     double det =   M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1))
00632                  - M(0,1)*(M(1,0)*M(2,2) - M(1,2)*M(2,0))
00633                  + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
00634 
00635     if (fabs(det)<Tol)
00636     {
00637         std::ostringstream oss;
00638         oss << PrintMatrix(M);
00639         throw new Fatal("matvec.h::Inv: 3x3 matrix inversion failed with null (%g) determinat. M =\n%s",Tol,oss.str().c_str());
00640     }
00641 
00642     Mi(0,0)=(M(1,1)*M(2,2)-M(1,2)*M(2,1))/det;  Mi(0,1)=(M(0,2)*M(2,1)-M(0,1)*M(2,2))/det;  Mi(0,2)=(M(0,1)*M(1,2)-M(0,2)*M(1,1))/det;
00643     Mi(1,0)=(M(1,2)*M(2,0)-M(1,0)*M(2,2))/det;  Mi(1,1)=(M(0,0)*M(2,2)-M(0,2)*M(2,0))/det;  Mi(1,2)=(M(0,2)*M(1,0)-M(0,0)*M(1,2))/det;
00644     Mi(2,0)=(M(1,0)*M(2,1)-M(1,1)*M(2,0))/det;  Mi(2,1)=(M(0,1)*M(2,0)-M(0,0)*M(2,1))/det;  Mi(2,2)=(M(0,0)*M(1,1)-M(0,1)*M(1,0))/det;
00645 }
00646 
00648 inline void Sol (Mat3_t const & M, Vec3_t const & B, Vec3_t & X, double Tol=1.0e-10)
00649 {
00650     // determinant
00651     double det =   M(0,0)*(M(1,1)*M(2,2) - M(1,2)*M(2,1))
00652                  - M(0,1)*(M(1,0)*M(2,2) - M(1,2)*M(2,0))
00653                  + M(0,2)*(M(1,0)*M(2,1) - M(1,1)*M(2,0));
00654     if (fabs(det)<Tol) throw new Fatal("matvec.h:Sol: Cannot calculate inverse due to zero determinant. det = %g",det);
00655 
00656     // inverse matrix
00657     Mat3_t Mi;
00658     Mi(0,0) = (M(1,1)*M(2,2) - M(1,2)*M(2,1)) / det;
00659     Mi(0,1) = (M(0,2)*M(2,1) - M(0,1)*M(2,2)) / det;
00660     Mi(0,2) = (M(0,1)*M(1,2) - M(0,2)*M(1,1)) / det;
00661 
00662     Mi(1,0) = (M(1,2)*M(2,0) - M(1,0)*M(2,2)) / det;
00663     Mi(1,1) = (M(0,0)*M(2,2) - M(0,2)*M(2,0)) / det;
00664     Mi(1,2) = (M(0,2)*M(1,0) - M(0,0)*M(1,2)) / det;
00665 
00666     Mi(2,0) = (M(1,0)*M(2,1) - M(1,1)*M(2,0)) / det;
00667     Mi(2,1) = (M(0,1)*M(2,0) - M(0,0)*M(2,1)) / det;
00668     Mi(2,2) = (M(0,0)*M(1,1) - M(0,1)*M(1,0)) / det;
00669 
00670     // solve system
00671     X(0) = Mi(0,0)*B(0) + Mi(0,1)*B(1) + Mi(0,2)*B(2);
00672     X(1) = Mi(1,0)*B(0) + Mi(1,1)*B(1) + Mi(1,2)*B(2);
00673     X(2) = Mi(2,0)*B(0) + Mi(2,1)*B(1) + Mi(2,2)*B(2);
00674 }
00675 
00677 inline void Eig (Mat3_t & M, Vec3_t & L)
00678 {
00679     // calculate
00680     gsl_matrix_view m = gsl_matrix_view_array (M.data(), 3, 3);
00681     gsl_vector * eval = gsl_vector_alloc      (3);
00682     gsl_eigen_symm_workspace * w = gsl_eigen_symm_alloc (3);
00683     gsl_eigen_symm (&m.matrix, eval, w);
00684 
00685     // eigenvalues
00686     L = gsl_vector_get(eval,0), gsl_vector_get(eval,1), gsl_vector_get(eval,2);
00687 
00688     // clean up
00689     gsl_eigen_symm_free (w);
00690     gsl_vector_free     (eval);
00691 }
00692 
00694 inline void Eig (Mat3_t & M, Vec3_t & L, Vec3_t & V0, Vec3_t & V1, Vec3_t & V2, bool SortAsc=false, bool SortDesc=false)
00695 {
00696     // calculate
00697     gsl_matrix_view m = gsl_matrix_view_array (M.data(), 3, 3);
00698     gsl_vector * eval = gsl_vector_alloc      (3);
00699     gsl_matrix * evec = gsl_matrix_alloc      (3, 3);
00700     gsl_eigen_symmv_workspace * w = gsl_eigen_symmv_alloc (3);
00701     gsl_eigen_symmv (&m.matrix, eval, evec, w);
00702 
00703     // sort
00704     if (SortAsc)  gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_VAL_ASC);
00705     if (SortDesc) gsl_eigen_symmv_sort (eval, evec, GSL_EIGEN_SORT_VAL_DESC);
00706 
00707     // eigenvalues
00708     L = gsl_vector_get(eval,0), gsl_vector_get(eval,1), gsl_vector_get(eval,2);
00709 
00710     // eigenvectors
00711     gsl_vector_view ev = gsl_matrix_column (evec,0);
00712     V0 = gsl_vector_get    (&ev.vector,0), gsl_vector_get(&ev.vector,1), gsl_vector_get(&ev.vector,2);
00713     ev = gsl_matrix_column (evec,1);
00714     V1 = gsl_vector_get    (&ev.vector,0), gsl_vector_get(&ev.vector,1), gsl_vector_get(&ev.vector,2);
00715     ev = gsl_matrix_column (evec,2);
00716     V2 = gsl_vector_get    (&ev.vector,0), gsl_vector_get(&ev.vector,1), gsl_vector_get(&ev.vector,2);
00717 
00718     // clean up
00719     gsl_eigen_symmv_free (w);
00720     gsl_vector_free      (eval);
00721     gsl_matrix_free      (evec);
00722 }
00723 
00725 inline double Norm (Vec3_t const & V)
00726 {
00727     return sqrt(blitz::dot(V,V));
00728 }
00729 
00731 inline void Dyad (Vec3_t const & A, Vec3_t const & B, Mat3_t & M)
00732 {
00733     M(0,0)=A(0)*B(0);  M(0,1)=A(0)*B(1);  M(0,2)=A(0)*B(2);
00734     M(1,0)=A(1)*B(0);  M(1,1)=A(1)*B(1);  M(1,2)=A(1)*B(2);
00735     M(2,0)=A(2)*B(0);  M(2,1)=A(2)*B(1);  M(2,2)=A(2)*B(2);
00736 }
00737 
00739 inline void Dyad (double s, Vec3_t const & A, Vec3_t const & B, Mat3_t & M)
00740 {
00741     M(0,0)=s*A(0)*B(0);  M(0,1)=s*A(0)*B(1);  M(0,2)=s*A(0)*B(2);
00742     M(1,0)=s*A(1)*B(0);  M(1,1)=s*A(1)*B(1);  M(1,2)=s*A(1)*B(2);
00743     M(2,0)=s*A(2)*B(0);  M(2,1)=s*A(2)*B(1);  M(2,2)=s*A(2)*B(2);
00744 }
00745 
00747 inline void Mult (Vec3_t const & A, Mat3_t const & M, Vec3_t & B)
00748 {
00749     B(0) = A(0)*M(0,0) + A(1)*M(1,0) + A(2)*M(2,0);
00750     B(1) = A(0)*M(0,1) + A(1)*M(1,1) + A(2)*M(2,1);
00751     B(2) = A(0)*M(0,2) + A(1)*M(1,2) + A(2)*M(2,2);
00752 }
00753 
00755 inline void Mult (Mat3_t const & A, Mat3_t const & B, Mat3_t & M)
00756 {
00757     M(0,0)=A(0,2)*B(2,0)+A(0,1)*B(1,0)+A(0,0)*B(0,0);  M(0,1)=A(0,2)*B(2,1)+A(0,1)*B(1,1)+A(0,0)*B(0,1);  M(0,2)=A(0,2)*B(2,2)+A(0,1)*B(1,2)+A(0,0)*B(0,2);
00758     M(1,0)=A(1,2)*B(2,0)+B(1,0)*A(1,1)+B(0,0)*A(1,0);  M(1,1)=A(1,2)*B(2,1)+A(1,1)*B(1,1)+B(0,1)*A(1,0);  M(1,2)=A(1,2)*B(2,2)+A(1,1)*B(1,2)+B(0,2)*A(1,0);
00759     M(2,0)=A(2,2)*B(2,0)+B(1,0)*A(2,1)+B(0,0)*A(2,0);  M(2,1)=B(2,1)*A(2,2)+B(1,1)*A(2,1)+B(0,1)*A(2,0);  M(2,2)=A(2,2)*B(2,2)+B(1,2)*A(2,1)+B(0,2)*A(2,0);
00760 }
00761 
00763 inline void set_to_zero (Vec3_t & V)
00764 {
00765     V = 0.0, 0.0, 0.0;
00766 }
00767 
00769 inline void set_to_zero (Mat3_t & M)
00770 {
00771     M = 0.0, 0.0, 0.0,
00772         0.0, 0.0, 0.0,
00773         0.0, 0.0, 0.0;
00774 }
00775 
00776 // Constants
00777 namespace OrthoSys
00778 {
00779     Vec3_t O;        
00780     Vec3_t e0,e1,e2; 
00781     Mat3_t I;        
00782 
00783     int __init_ortho_sys()
00784     {
00785         O  = 0.0, 0.0, 0.0;
00786         e0 = 1.0, 0.0, 0.0;
00787         e1 = 0.0, 1.0, 0.0;
00788         e2 = 0.0, 0.0, 1.0;
00789         I  = 1.0, 0.0, 0.0,
00790              0.0, 1.0, 0.0,
00791              0.0, 0.0, 1.0;
00792         return 0.0;
00793     }
00794 
00795     int __dummy_init_ortho_sys = __init_ortho_sys();
00796 }
00797 
00798 #ifdef USE_BOOST_PYTHON
00799 inline Vec3_t Tup2Vec3 (BPy::tuple const & T3)
00800 {
00801     return Vec3_t(BPy::extract<double>(T3[0])(), BPy::extract<double>(T3[1])(), BPy::extract<double>(T3[2])());
00802 }
00803 #endif
00804 
00805 
00807 
00808 
00810 inline void Ten2Mat (Vec_t const & Ten, Mat3_t & Mat)
00811 {
00812     // matrix of tensor
00813     size_t ncp = size(Ten);
00814     if (ncp==4)
00815     {
00816         Mat = Ten(0),            Ten(3)/Util::SQ2,     0.0,
00817               Ten(3)/Util::SQ2,  Ten(1),               0.0,
00818                            0.0,               0.0,  Ten(2);
00819     }
00820     else if (ncp==6)
00821     {
00822         Mat = Ten(0),            Ten(3)/Util::SQ2,  Ten(5)/Util::SQ2,
00823               Ten(3)/Util::SQ2,  Ten(1),            Ten(4)/Util::SQ2,
00824               Ten(5)/Util::SQ2,  Ten(4)/Util::SQ2,  Ten(2);
00825         
00826     }
00827     else throw new Fatal("matvec.h::Ten2Mat: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
00828 }
00829 
00831 inline void Ten2Mat (Vec_t const & Ten, Mat_t & Mat)
00832 {
00833     // matrix of tensor
00834     Mat.change_dim (3,3);
00835     size_t ncp = size(Ten);
00836     if (ncp==4)
00837     {
00838         Mat = Ten(0),            Ten(3)/Util::SQ2,     0.0,
00839               Ten(3)/Util::SQ2,  Ten(1),               0.0,
00840                            0.0,               0.0,  Ten(2);
00841     }
00842     else if (ncp==6)
00843     {
00844         Mat = Ten(0),            Ten(3)/Util::SQ2,  Ten(5)/Util::SQ2,
00845               Ten(3)/Util::SQ2,  Ten(1),            Ten(4)/Util::SQ2,
00846               Ten(5)/Util::SQ2,  Ten(4)/Util::SQ2,  Ten(2);
00847         
00848     }
00849     else throw new Fatal("matvec.h::Ten2Mat: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
00850 }
00851 
00853 inline void Mat2Ten (Mat3_t const & Mat, Vec_t & Ten, size_t NumComponents, bool CheckSymmetry=true, double Tol=1.0e-10)
00854 {
00855     if (CheckSymmetry)
00856     {
00857         if (fabs(Mat(0,1)-Mat(1,0))>Tol) throw new Fatal("matvec.h::Mat2Ten: Matrix is not symmetric");
00858         if (fabs(Mat(1,2)-Mat(2,1))>Tol) throw new Fatal("matvec.h::Mat2Ten: Matrix is not symmetric");
00859         if (fabs(Mat(2,0)-Mat(0,2))>Tol) throw new Fatal("matvec.h::Mat2Ten: Matrix is not symmetric");
00860     }
00861 
00862     // tensor from matrix
00863     Ten.change_dim (NumComponents);
00864     if (NumComponents==4)
00865     {
00866         Ten = Mat(0,0), Mat(1,1), Mat(2,2), Util::SQ2*Mat(0,1);
00867     }
00868     else if (NumComponents==6)
00869     {
00870         Ten = Mat(0,0), Mat(1,1), Mat(2,2), Util::SQ2*Mat(0,1), Util::SQ2*Mat(1,2), Util::SQ2*Mat(2,0);
00871     }
00872     else throw new Fatal("matvec.h::Mat2Ten: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
00873 }
00874 
00875 #ifdef HAS_TENSORS
00876 
00878 inline void Vec2Tensor (Vec_t const & V, Ten1_t & Vec)
00879 {
00880     if (size(V)!=3) throw new Fatal("matvec.h::Ten1Tensor: Vector (Vec_t) must have size equal to 3");
00881     Vec = V(0), V(1), V(2);
00882 }
00883 
00885 inline void Vec2Tensor (Vec3_t const & V, Ten1_t & Vec)
00886 {
00887     Vec = V(0), V(1), V(2);
00888 }
00889 
00891 inline void Tensor2Vec (Ten1_t const & V, Vec_t & Vec)
00892 {
00893     Vec.change_dim (3);
00894     Vec = V[0], V[1], V[2];
00895 }
00896 
00898 inline void Tensor2Vec (Ten1_t const & V, Vec3_t & Vec)
00899 {
00900     Vec = V[0], V[1], V[2];
00901 }
00902 
00904 inline void Tensor2Mat (Ten2_t const & T, Mat3_t & M)
00905 {
00906     M = T[0][0],  T[0][1],  T[0][2],
00907         T[1][0],  T[1][1],  T[1][2],
00908         T[2][0],  T[2][1],  T[2][2];
00909 }
00910 
00912 inline void Mat2Tensor (Mat3_t const & M, Ten2_t & T)
00913 {
00914     T = M(0,0),  M(0,1),  M(0,2),
00915         M(1,0),  M(1,1),  M(1,2),
00916         M(2,0),  M(2,1),  M(2,2);
00917 }
00918 
00920 inline void Ten2Tensor (Vec_t const & Ten, Ten2_t & T)
00921 {
00922     size_t ncp = size(Ten);
00923     if (ncp==4)
00924     {
00925         T = Ten(0),            Ten(3)/Util::SQ2,     0.0,
00926             Ten(3)/Util::SQ2,  Ten(1),               0.0,
00927                          0.0,               0.0,  Ten(2);
00928     }
00929     else if (ncp==6)
00930     {
00931         T = Ten(0),            Ten(3)/Util::SQ2,  Ten(5)/Util::SQ2,
00932             Ten(3)/Util::SQ2,  Ten(1),            Ten(4)/Util::SQ2,
00933             Ten(5)/Util::SQ2,  Ten(4)/Util::SQ2,  Ten(2);
00934     }
00935     else throw new Fatal("matvec.h::Ten2Tensor: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation. NumComponents==%d is invalid",ncp);
00936 }
00937 
00939 inline void Tensor2Ten (Ten2_t const & T, Vec_t & Ten, size_t NumComponents, bool CheckSymmetry=true, double Tol=1.0e-10)
00940 {
00941     if (CheckSymmetry)
00942     {
00943         bool error = false;
00944         if (fabs(T[0][1]-T[1][0])>Tol) error = true;
00945         if (fabs(T[1][2]-T[2][1])>Tol) error = true;
00946         if (fabs(T[2][0]-T[0][2])>Tol) error = true;
00947         if (error)
00948         {
00949             Mat3_t mT;
00950             Tensor2Mat (T, mT);
00951             std::ostringstream oss;
00952             oss << "T = \n" << PrintMatrix(mT);
00953             throw new Fatal("matvec.h::Tensor2Ten: Tensor is not symmetric\n%s",oss.str().c_str());
00954         }
00955     }
00956 
00957     Ten.change_dim (NumComponents);
00958     if (NumComponents==4)
00959     {
00960         Ten = T[0][0], T[1][1], T[2][2], T[0][1]*Util::SQ2;
00961     }
00962     else if (NumComponents==6)
00963     {
00964         Ten = T[0][0], T[1][1], T[2][2], T[0][1]*Util::SQ2, T[1][2]*Util::SQ2, T[2][0]*Util::SQ2;
00965     }
00966     else throw new Fatal("matvec.h::Tensor2Ten: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation. NumComponents==%d is invalid",NumComponents);
00967 }
00968 
00970 inline void Tensor2Ten (Ten4_t const & T, Mat_t & Ten, size_t NumComponents, bool CheckSymmetry=true, double Tol=1.0e-10)
00971 {
00972     if (!(NumComponents==4 || NumComponents==6)) throw new Fatal("matvec.h::Tensor2Ten: This method is only available for 4th order symmetric tensors with either 4x4 or 6x6 components according to Mandel's representation. NumComponents==%d is invalid",NumComponents);
00973     Ten.change_dim (NumComponents,NumComponents);
00974     for (size_t i=0; i<3; ++i)
00975     for (size_t j=0; j<3; ++j)
00976     for (size_t k=0; k<3; ++k)
00977     for (size_t l=0; l<3; ++l)
00978     {
00979         if (CheckSymmetry)
00980         {
00981             if (fabs(T[i][j][k][l] - T[i][j][l][k])>Tol) throw new Fatal("matvec.h::Tensor2Ten: 4ht order Tensor is not super symmetric: ijkl != ijlk");
00982             if (fabs(T[i][j][k][l] - T[j][i][k][l])>Tol) throw new Fatal("matvec.h::Tensor2Ten: 4ht order Tensor is not super symmetric: ijkl != jikl");
00983             if (fabs(T[i][j][k][l] - T[k][l][i][j])>Tol) throw new Fatal("matvec.h::Tensor2Ten: 4ht order Tensor is not super symmetric: ijkl != klij");
00984         }
00985         size_t I = TensorsLib::Tensor4ToMandel_i[i][j][k][l];
00986         size_t J = TensorsLib::Tensor4ToMandel_j[i][j][k][l];
00987         double a = (k==l ? 1.0 : Util::SQ2);
00988         double b = (i==j ? 1.0 : Util::SQ2);
00989         if (I<NumComponents && J<NumComponents) Ten(I,J) = T[i][j][k][l]*a*b;
00990     }
00991 }
00992 
00993 #endif
00994 
00995 
00997 
00998 
01000 inline void UnitVecDeriv (Vec_t const & n, Vec_t & nu, Mat_t & dnudn, double Tol=1.0e-8)
01001 {
01002     double norm_n = Norm(n);
01003     Mat_t I;
01004     Identity (size(n), I);
01005     if (norm_n>Tol)
01006     {
01007         nu = n / norm_n;
01008         Mat_t nu_dy_nu;
01009         Dyad (nu, nu, nu_dy_nu);
01010         dnudn = I/norm_n - nu_dy_nu/norm_n;
01011     }
01012     else
01013     {
01014         nu    = 1./Util::SQ3, 1./Util::SQ3, 1./Util::SQ3;
01015         dnudn = I;
01016     }
01017 }
01018 
01020 inline void UnitVecDeriv (Vec3_t const & n, Vec3_t & nu, Mat3_t & dnudn, double Tol=1.0e-8)
01021 {
01022     double norm_n = Norm(n);
01023     if (norm_n>Tol)
01024     {
01025         double s = 1.0/norm_n;
01026         nu = n / norm_n;
01027         dnudn(0,0)=s-s*nu(0)*nu(0);   dnudn(0,1)= -s*nu(0)*nu(1);   dnudn(0,2)= -s*nu(0)*nu(2);
01028         dnudn(1,0)= -s*nu(1)*nu(0);   dnudn(1,1)=s-s*nu(1)*nu(1);   dnudn(1,2)= -s*nu(1)*nu(2);
01029         dnudn(2,0)= -s*nu(2)*nu(0);   dnudn(2,1)= -s*nu(2)*nu(1);   dnudn(2,2)=s-s*nu(2)*nu(2);
01030     }
01031     else
01032     {
01033         nu    = 1./Util::SQ3, 1./Util::SQ3, 1./Util::SQ3;
01034         dnudn = 1.0, 0.0, 0.0,
01035                 0.0, 1.0, 0.0,
01036                 0.0, 0.0, 1.0;
01037     }
01038 }
01039 
01040 #ifdef HAS_TENSORS
01041 
01043 inline void UnitVecDeriv (Vec3_t const & n, Vec3_t & nu, Ten2_t & dnudn, double Tol=1.0e-8)
01044 {
01045     double norm_n = Norm(n);
01046     if (norm_n>Tol)
01047     {
01048         double s = 1.0/norm_n;
01049         nu = n / norm_n;
01050         dnudn[0][0]=s-s*nu(0)*nu(0);   dnudn[0][1]= -s*nu(0)*nu(1);   dnudn[0][2]= -s*nu(0)*nu(2);
01051         dnudn[1][0]= -s*nu(1)*nu(0);   dnudn[1][1]=s-s*nu(1)*nu(1);   dnudn[1][2]= -s*nu(1)*nu(2);
01052         dnudn[2][0]= -s*nu(2)*nu(0);   dnudn[2][1]= -s*nu(2)*nu(1);   dnudn[2][2]=s-s*nu(2)*nu(2);
01053     }
01054     else
01055     {
01056         nu    = 1./Util::SQ3, 1./Util::SQ3, 1./Util::SQ3;
01057         dnudn = 1.0, 0.0, 0.0,
01058                 0.0, 1.0, 0.0,
01059                 0.0, 0.0, 1.0;
01060     }
01061 }
01062 
01063 #endif
01064 
01065 
01067 
01068 
01069 // Assymmetric 3D tensor
01070 typedef blitz::TinyVector<double,9> ATensor2; 
01071 
01073 inline void Sym (double a, ATensor2 const & T,  size_t NCp, Vec_t & S)
01074 {
01075     S.change_dim (NCp);
01076     if (NCp==4)
01077     {
01078         S(0) = a*T(0);
01079         S(1) = a*T(1);
01080         S(2) = a*T(2);
01081         S(3) = a*0.5*(T(3)+T(6))*Util::SQ2;
01082     }
01083     else if (NCp==6)
01084     {
01085         S(0) = a*T(0);
01086         S(1) = a*T(1);
01087         S(2) = a*T(2);
01088         S(3) = a*0.5*(T(3)+T(6))*Util::SQ2;
01089         S(4) = a*0.5*(T(4)+T(7))*Util::SQ2;
01090         S(5) = a*0.5*(T(5)+T(8))*Util::SQ2;
01091     }
01092     else throw new Fatal("matvec.h::Sym: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation. NCp=%zd is invalid",NCp);
01093 }
01094 
01096 inline void Dot (ATensor2 const & A, ATensor2 const & B,  ATensor2 & C)
01097 {
01098     C(0) = A(0)*B(0)+A(3)*B(6)+A(5)*B(8);
01099     C(3) = A(0)*B(3)+A(3)*B(1)+A(5)*B(7);
01100     C(5) = A(0)*B(5)+A(3)*B(4)+A(5)*B(2);
01101     C(6) = A(6)*B(0)+A(1)*B(6)+A(4)*B(8);
01102     C(1) = A(6)*B(3)+A(1)*B(1)+A(4)*B(7);
01103     C(4) = A(6)*B(5)+A(1)*B(4)+A(4)*B(2);
01104     C(8) = A(8)*B(0)+A(7)*B(6)+A(2)*B(8);
01105     C(7) = A(8)*B(3)+A(7)*B(1)+A(2)*B(7);
01106     C(2) = A(8)*B(5)+A(7)*B(4)+A(2)*B(2);
01107 }
01108 
01110 inline void AddSkewTimesOp1 (ATensor2 const & L, Vec_t const & S,  Vec_t & R, double Tol=1.0e-14)
01111 {
01112     size_t ncp = size(R);
01113     if (ncp==4)
01114     {
01115         R(0) += -(Util::SQ2*S(3)*L(6)-Util::SQ2*L(3)*S(3))/2.0;
01116         R(1) +=  (Util::SQ2*S(3)*L(6)-Util::SQ2*L(3)*S(3))/2.0;
01117         R(2) +=  0.0;
01118         R(3) += -((S(1)-S(0))*L(6)+(S(0)-S(1))*L(3))/Util::SQ2;
01119         double R4 = (Util::SQ2*S(3)*L(8)+(2*S(1)-2*S(2))*L(7)-Util::SQ2*S(3)*L(5)+(2*S(2)-2*S(1))*L(4))/(2.0*Util::SQ2);
01120         double R5 = -((2*S(2)-2*S(0))*L(8)-Util::SQ2*S(3)*L(7)+(2*S(0)-2*S(2))*L(5)+Util::SQ2*S(3)*L(4))/(2.0*Util::SQ2);
01121         if (fabs(R4)>Tol) throw new Fatal("matvec.h::SkewTimesOp1: R4=%g is not zero => Tensor cannot be represented by 4 components only",R4);
01122         if (fabs(R5)>Tol) throw new Fatal("matvec.h::SkewTimesOp1: R5=%g is not zero => Tensor cannot be represented by 5 components only",R5);
01123     }
01124     else if (ncp==6)
01125     {
01126         R(0) += -(Util::SQ2*S(5)*L(8)+Util::SQ2*S(3)*L(6)-Util::SQ2*L(5)*S(5)-Util::SQ2*L(3)*S(3))/2.0;
01127         R(1) += -(Util::SQ2*S(4)*L(7)-Util::SQ2*S(3)*L(6)-Util::SQ2*L(4)*S(4)+Util::SQ2*L(3)*S(3))/2.0;
01128         R(2) +=  (Util::SQ2*S(5)*L(8)+Util::SQ2*S(4)*L(7)-Util::SQ2*L(5)*S(5)-Util::SQ2*L(4)*S(4))/2.0;
01129         R(3) += -(Util::SQ2*S(4)*L(8)+Util::SQ2*S(5)*L(7)+(2*S(1)-2*S(0))*L(6)-Util::SQ2*L(4)*S(5)-Util::SQ2*S(4)*L(5)+(2*S(0)-2*S(1))*L(3))/(2.0*Util::SQ2);
01130         R(4) +=  (Util::SQ2*S(3)*L(8)+(2*S(1)-2*S(2))*L(7)+Util::SQ2*S(5)*L(6)-Util::SQ2*L(3)*S(5)-Util::SQ2*S(3)*L(5)+(2*S(2)-2*S(1))*L(4))/(2.0*Util::SQ2);
01131         R(5) += -((2*S(2)-2*S(0))*L(8)-Util::SQ2*S(3)*L(7)+Util::SQ2*S(4)*L(6)+(2*S(0)-2*S(2))*L(5)-Util::SQ2*L(3)*S(4)+Util::SQ2*S(3)*L(4))/(2.0*Util::SQ2);
01132     }
01133     else throw new Fatal("matvec.h::SkewTimesOp1: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation. NCp=%zd is invalid",ncp);
01134 }
01135 
01137 inline double Det (ATensor2 const & F)
01138 {
01139     return -F(3)*(F(2)*F(6)-F(4)*F(8)) + F(5)*(F(6)*F(7)-F(1)*F(8)) + F(0)*(F(1)*F(2)-F(4)*F(7));
01140 }
01141 
01143 inline void CalcLCauchyGreen (ATensor2 const & F,  size_t NCp, Vec_t & b, double Tol=1.0e-14)
01144 {
01145     b.change_dim (NCp);
01146     if (NCp==4)
01147     {
01148         b(0) = pow(F(5),2.0)+pow(F(3),2.0)+pow(F(0),2.0);
01149         b(1) = pow(F(6),2.0)+pow(F(4),2.0)+pow(F(1),2.0);
01150         b(2) = pow(F(8),2.0)+pow(F(7),2.0)+pow(F(2),2.0);
01151         b(3) = Util::SQ2*F(0)*F(6)+Util::SQ2*F(4)*F(5)+Util::SQ2*F(1)*F(3);
01152         double b4 = Util::SQ2*F(6)*F(8)+Util::SQ2*F(1)*F(7)+Util::SQ2*F(2)*F(4);
01153         double b5 = Util::SQ2*F(0)*F(8)+Util::SQ2*F(3)*F(7)+Util::SQ2*F(2)*F(5);
01154         if (fabs(b4)>Tol) throw new Fatal("matvec.h::CalcLCauchyGreen: b4=%g is not zero => Tensor cannot be represented by 4 components only",b4);
01155         if (fabs(b5)>Tol) throw new Fatal("matvec.h::CalcLCauchyGreen: b5=%g is not zero => Tensor cannot be represented by 5 components only",b5);
01156     }
01157     else if (NCp==6)
01158     {
01159         b(0) = pow(F(5),2.0)+pow(F(3),2.0)+pow(F(0),2.0);
01160         b(1) = pow(F(6),2.0)+pow(F(4),2.0)+pow(F(1),2.0);
01161         b(2) = pow(F(8),2.0)+pow(F(7),2.0)+pow(F(2),2.0);
01162         b(3) = Util::SQ2*F(0)*F(6)+Util::SQ2*F(4)*F(5)+Util::SQ2*F(1)*F(3);
01163         b(4) = Util::SQ2*F(6)*F(8)+Util::SQ2*F(1)*F(7)+Util::SQ2*F(2)*F(4);
01164         b(5) = Util::SQ2*F(0)*F(8)+Util::SQ2*F(3)*F(7)+Util::SQ2*F(2)*F(5);
01165     }
01166     else throw new Fatal("matvec.h::CalcLCauchyGreen: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation. NCp=%zd is invalid",NCp);
01167 }
01168 
01169 
01171 inline void Mult (Vec_t const & Sig, Vec3_t const & n, Vec3_t & t)
01172 {
01173     size_t ncp = size(Sig);
01174     if (ncp==4)
01175     {
01176         t(0) = Sig(0)*n(0)           + Sig(3)*n(1)/Util::SQ2;
01177         t(1) = Sig(3)*n(0)/Util::SQ2 + Sig(1)*n(1);
01178         t(2) =                                               + Sig(2)*n(2);
01179     }
01180     else if (ncp==6)
01181     {
01182         t(0) = Sig(0)*n(0)           + Sig(3)*n(1)/Util::SQ2 + Sig(5)*n(2)/Util::SQ2;
01183         t(1) = Sig(3)*n(0)/Util::SQ2 + Sig(1)*n(1)           + Sig(4)*n(2)/Util::SQ2;
01184         t(2) = Sig(5)*n(0)/Util::SQ2 + Sig(4)*n(1)/Util::SQ2 + Sig(2)*n(2);
01185     }
01186     else throw new Fatal("matvec.h::Mult: (Cauchy) This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01187 }
01188 
01190 inline void Dev (Vec_t const & Ten, Vec_t & DevTen)
01191 {
01192     double coef = (Ten(0)+Ten(1)+Ten(2))/3.0;
01193     DevTen     = Ten;
01194     DevTen(0) -= coef;
01195     DevTen(1) -= coef;
01196     DevTen(2) -= coef;
01197 }
01198 
01200 inline double Tra (Vec_t const & Ten)
01201 {
01202     return Ten(0)+Ten(1)+Ten(2);
01203 }
01204 
01206 inline void Pow2 (Vec_t const & Ten, Vec_t & Ten2)
01207 {
01208     size_t ncp = size(Ten);
01209     Ten2.change_dim (ncp);
01210     if (ncp==4)
01211     {
01212         Ten2 = Ten(0)*Ten(0) + Ten(3)*Ten(3)/2.0,
01213                Ten(1)*Ten(1) + Ten(3)*Ten(3)/2.0,
01214                Ten(2)*Ten(2),
01215                Ten(0)*Ten(3) + Ten(1)*Ten(3);
01216     }
01217     else if (ncp==6)
01218     {
01219         Ten2 = Ten(0)*Ten(0)           + Ten(3)*Ten(3)/2.0       + Ten(5)*Ten(5)/2.0,
01220                Ten(3)*Ten(3)/2.0       + Ten(1)*Ten(1)           + Ten(4)*Ten(4)/2.0,
01221                Ten(5)*Ten(5)/2.0       + Ten(4)*Ten(4)/2.0       + Ten(2)*Ten(2),
01222                Ten(0)*Ten(3)           + Ten(3)*Ten(1)           + Ten(5)*Ten(4)/Util::SQ2,
01223                Ten(3)*Ten(5)/Util::SQ2 + Ten(1)*Ten(4)           + Ten(4)*Ten(2),
01224                Ten(0)*Ten(5)           + Ten(3)*Ten(4)/Util::SQ2 + Ten(5)*Ten(2);
01225     }
01226     else throw new Fatal("matvec.h::Pow2: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01227 }
01228 
01230 inline double Det (Vec_t const & Ten)
01231 {
01232     size_t ncp = size(Ten);
01233     if (ncp==4)
01234     {
01235         return   Ten(0)*Ten(1)*Ten(2)
01236                - Ten(2)*Ten(3)*Ten(3)/2.0;
01237     }
01238     else if (ncp==6)
01239     {
01240         return   Ten(0)*Ten(1)*Ten(2) 
01241                + Ten(3)*Ten(4)*Ten(5)/Util::SQ2
01242                - Ten(0)*Ten(4)*Ten(4)/2.0
01243                - Ten(1)*Ten(5)*Ten(5)/2.0
01244                - Ten(2)*Ten(3)*Ten(3)/2.0;
01245     }
01246     else throw new Fatal("matvec.h::Det: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01247 }
01248 
01250 inline void Inv (Vec_t const & T, Vec_t & Ti, double Tol=1.0e-10)
01251 {
01252     size_t ncp = size(T);
01253     Ti.change_dim (ncp);
01254     if (ncp==4)
01255     {
01256         double det =  T(0)*T(1)*T(2)
01257                     - T(2)*T(3)*T(3)/2.0;
01258 
01259         if (fabs(det)<Tol)
01260         {
01261             std::ostringstream oss;  oss<<PrintVector(T);
01262             throw new Fatal("matvec.h::Inv: inverse of 2nd order symmetric tensor failed with null (%g) determinat.\n  T =%s",Tol,oss.str().c_str());
01263         }
01264 
01265         Ti(0) =  T(1)*T(2)/det;
01266         Ti(1) =  T(0)*T(2)/det;
01267         Ti(2) = (T(0)*T(1) - T(3)*T(3)/2.0)/det;
01268         Ti(3) = -T(2)*T(3)/det;
01269 
01270     }
01271     else if (ncp==6)
01272     {
01273         double det =  T(0)*T(1)*T(2) 
01274                     + T(3)*T(4)*T(5)/Util::SQ2
01275                     - T(0)*T(4)*T(4)/2.0
01276                     - T(1)*T(5)*T(5)/2.0
01277                     - T(2)*T(3)*T(3)/2.0;
01278 
01279         if (fabs(det)<Tol)
01280         {
01281             std::ostringstream oss;  oss<<PrintVector(T);
01282             throw new Fatal("matvec.h::Inv: inverse of 2nd order symmetric tensor failed with null (%g) determinat.\n  T =%s",Tol,oss.str().c_str());
01283         }
01284 
01285         Ti(0) = (T(1)*T(2) - T(4)*T(4)/2.0)/det;
01286         Ti(1) = (T(0)*T(2) - T(5)*T(5)/2.0)/det;
01287         Ti(2) = (T(0)*T(1) - T(3)*T(3)/2.0)/det;
01288         Ti(3) = (T(4)*T(5)/Util::SQ2 - T(2)*T(3))/det;
01289         Ti(4) = (T(3)*T(5)/Util::SQ2 - T(0)*T(4))/det;
01290         Ti(5) = (T(3)*T(4)/Util::SQ2 - T(1)*T(5))/det;
01291     }
01292     else throw new Fatal("matvec.h::Inv: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01293 }
01294 
01296 inline void CharInvs (Vec_t const & Ten, double & I1, double & I2, double & I3)
01297 {
01298     I1 = Ten(0) + Ten(1) + Ten(2);
01299     I2 = Ten(0)*Ten(1) + Ten(1)*Ten(2) + Ten(2)*Ten(0) - Ten(3)*Ten(3)/2.0;
01300     I3 = Ten(0)*Ten(1)*Ten(2) - Ten(2)*Ten(3)*Ten(3)/2.0;
01301     size_t ncp = size(Ten);
01302     if (ncp>4)
01303     {
01304         I2 += (-Ten(4)*Ten(4)/2.0 - Ten(5)*Ten(5)/2.0);
01305         I3 += (Ten(3)*Ten(4)*Ten(5)/Util::SQ2 - Ten(0)*Ten(4)*Ten(4)/2.0 - Ten(1)*Ten(5)*Ten(5)/2.0);
01306     }
01307 }
01308 
01310 inline void CharInvs (Vec_t const & Ten, double & I1, double & I2, double & I3, Vec_t & dI1dTen, Vec_t & dI2dTen, Vec_t & dI3dTen)
01311 {
01312     I1 = Ten(0) + Ten(1) + Ten(2);
01313     I2 = Ten(0)*Ten(1) + Ten(1)*Ten(2) + Ten(2)*Ten(0) - Ten(3)*Ten(3)/2.0;
01314     I3 = Ten(0)*Ten(1)*Ten(2) - Ten(2)*Ten(3)*Ten(3)/2.0;
01315     size_t ncp = size(Ten);
01316     dI1dTen.change_dim (ncp);
01317     dI2dTen.change_dim (ncp);
01318     dI3dTen.change_dim (ncp);
01319     if (ncp>4)
01320     {
01321         I2 += (-Ten(4)*Ten(4)/2.0 - Ten(5)*Ten(5)/2.0);
01322         I3 += (Ten(3)*Ten(4)*Ten(5)/Util::SQ2 - Ten(0)*Ten(4)*Ten(4)/2.0 - Ten(1)*Ten(5)*Ten(5)/2.0);
01323         dI1dTen = 1.0, 1.0, 1.0, 0.0, 0.0, 0.0;
01324     }
01325     else dI1dTen = 1.0, 1.0, 1.0, 0.0;
01326     Vec_t Ten2(ncp);
01327     Pow2 (Ten, Ten2);
01328     dI2dTen = I1*dI1dTen - Ten;
01329     dI3dTen = Ten2 - I1*Ten + I2*dI1dTen;
01330 }
01331 
01333 inline void DerivInv (Vec_t const & A, Vec_t & Ai, Mat_t & dInvA_dA, double Tol=1.0e-10)
01334 {
01335     Inv (A, Ai, Tol);
01336     size_t ncp = size(A);
01337     dInvA_dA.change_dim (ncp,ncp);
01338     if (ncp==4) throw new Fatal("matvec.h: DerivInv: This method doesn't work for ncp==4");
01339     else if (ncp==6)
01340     {
01341         double s = Util::SQ2;
01342         dInvA_dA =
01343             -Ai(0)*Ai(0)     , -Ai(3)*Ai(3)/2.  , -Ai(5)*Ai(5)/2.  , -Ai(0)*Ai(3)                      , -(Ai(3)*Ai(5))/s                  , -Ai(0)*Ai(5)                      , 
01344             -Ai(3)*Ai(3)/2.  , -Ai(1)*Ai(1)     , -Ai(4)*Ai(4)/2.  , -Ai(1)*Ai(3)                      , -Ai(1)*Ai(4)                      , -(Ai(3)*Ai(4))/s                  , 
01345             -Ai(5)*Ai(5)/2.  , -Ai(4)*Ai(4)/2.  , -Ai(2)*Ai(2)     , -(Ai(4)*Ai(5))/s                  , -Ai(2)*Ai(4)                      , -Ai(2)*Ai(5)                      , 
01346             -Ai(0)*Ai(3)     , -Ai(1)*Ai(3)     , -(Ai(4)*Ai(5))/s , -Ai(3)*Ai(3)/2.-Ai(0)*Ai(1)       , -(Ai(1)*Ai(5))/s-(Ai(3)*Ai(4))/2. , -(Ai(3)*Ai(5))/2.-(Ai(0)*Ai(4))/s , 
01347             -(Ai(3)*Ai(5))/s , -Ai(1)*Ai(4)     , -Ai(2)*Ai(4)     , -(Ai(1)*Ai(5))/s-(Ai(3)*Ai(4))/2. , -Ai(4)*Ai(4)/2.-Ai(1)*Ai(2)       , -(Ai(4)*Ai(5))/2.-(Ai(2)*Ai(3))/s , 
01348             -Ai(0)*Ai(5)     , -(Ai(3)*Ai(4))/s , -Ai(2)*Ai(5)     , -(Ai(3)*Ai(5))/2.-(Ai(0)*Ai(4))/s , -(Ai(4)*Ai(5))/2.-(Ai(2)*Ai(3))/s , -Ai(5)*Ai(5)/2.-Ai(0)*Ai(2)       ;
01349     }
01350     else throw new Fatal("matvec.h::DerivInv: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01351 }
01352 
01354 inline void Eig (Vec_t const & Ten, Vec3_t & L, Vec3_t & V0, Vec3_t & V1, Vec3_t & V2, bool SortAsc=false, bool SortDesc=false)
01355 {
01356     Mat3_t M;
01357     Ten2Mat (Ten, M);
01358     Eig (M, L, V0, V1, V2, SortAsc, SortDesc);
01359 }
01360 
01362 inline void EigenProj (Vec_t const & Ten, Vec3_t & L, Vec3_t & v0, Vec3_t & v1, Vec3_t & v2, Vec_t & P0, Vec_t & P1, Vec_t & P2, bool SortAsc=false, bool SortDesc=false)
01363 {
01364     // matrix of tensor
01365     Mat3_t ten;
01366     Ten2Mat (Ten, ten);
01367 
01368     // eigen-values and vectors
01369     Eig (ten, L, v0, v1, v2, SortAsc, SortDesc);
01370 
01371     // eigen-projectors
01372     size_t ncp = size(Ten);
01373     P0.change_dim (ncp);
01374     P1.change_dim (ncp);
01375     P2.change_dim (ncp);
01376     if (ncp==4)
01377     {
01378         P0 = v0(0)*v0(0), v0(1)*v0(1), v0(2)*v0(2), v0(0)*v0(1)*Util::SQ2;
01379         P1 = v1(0)*v1(0), v1(1)*v1(1), v1(2)*v1(2), v1(0)*v1(1)*Util::SQ2;
01380         P2 = v2(0)*v2(0), v2(1)*v2(1), v2(2)*v2(2), v2(0)*v2(1)*Util::SQ2;
01381     }
01382     else
01383     {
01384         P0 = v0(0)*v0(0), v0(1)*v0(1), v0(2)*v0(2), v0(0)*v0(1)*Util::SQ2, v0(1)*v0(2)*Util::SQ2, v0(2)*v0(0)*Util::SQ2;
01385         P1 = v1(0)*v1(0), v1(1)*v1(1), v1(2)*v1(2), v1(0)*v1(1)*Util::SQ2, v1(1)*v1(2)*Util::SQ2, v1(2)*v1(0)*Util::SQ2;
01386         P2 = v2(0)*v2(0), v2(1)*v2(1), v2(2)*v2(2), v2(0)*v2(1)*Util::SQ2, v2(1)*v2(2)*Util::SQ2, v2(2)*v2(0)*Util::SQ2;
01387     }
01388 }
01389 
01391 inline void EigenProjAnalytic (Vec_t const & Ten, Vec3_t & L, Vec_t & P0, Vec_t & P1, Vec_t & P2)
01392 {
01393     // identity tensor
01394     size_t ncp = size(Ten);
01395     Vec_t I(ncp);
01396     set_to_zero(I);
01397     I(0)=1.0;  I(1)=1.0;  I(2)=1.0;
01398 
01399     // characteristics invariants
01400     double I1,I2,I3;
01401     CharInvs (Ten,I1,I2,I3);
01402 
01403     // inverse tensor
01404     Vec_t Ti;
01405     Inv (Ten, Ti);
01406 
01407     // eigen-values/projectors
01408     P0.change_dim (ncp);
01409     P1.change_dim (ncp);
01410     P2.change_dim (ncp);
01411     Vec_t * P[3] = {&P0, &P1, &P2}; // all three eigen projectors
01412     double alpha = 2.0*sqrt(I1*I1-3.0*I2);
01413     double theta = acos((2.0*I1*I1*I1-9.0*I1*I2+27.0*I3)/(2.0*pow(I1*I1-3.0*I2,3.0/2.0)));
01414     //std::cout << "I1 = " << I1 << ",  I2 = " << I2 << ",  I3 = " << I3 << ",  I1*I1-3*I2 = " << I1*I1-3.0*I2 << std::endl;
01415     //std::cout << "alpha = " << alpha << ",  theta = " << theta << std::endl;
01416     for (size_t k=0; k<3; ++k)
01417     {
01418         L(k) = (I1+alpha*cos((theta+2.0*Util::PI*(1.0+k))/3.0))/3.0;
01419         if (fabs(L(k))<1.0e-14) throw new Fatal("matvec.h:EigenProjAnalytic: L(%d)=%g must be non-zero",k,L(k));
01420         double coef = L(k)/(2.0*L(k)*L(k)-L(k)*I1+I3/L(k));
01421         (*P[k]) = coef*(Ten+(L(k)-I1)*I+(I3/L(k))*Ti);
01422     }
01423 }
01424 
01426 inline void Calc_I (size_t NCp, Vec_t & I)
01427 {
01428     I.change_dim(NCp);
01429     if      (NCp==4) I = 1.0, 1.0, 1.0, 0.0;
01430     else if (NCp==6) I = 1.0, 1.0, 1.0, 0.0, 0.0, 0.0;
01431     else throw new Fatal("matvec.h::Calc_I: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01432 }
01433 
01435 inline void Calc_IIsym (size_t NCp, Mat_t & IIsym)
01436 {
01437     IIsym.change_dim(NCp,NCp);
01438     if (NCp==4)
01439     {
01440         IIsym = 1.0, 0.0, 0.0, 0.0,
01441                 0.0, 1.0, 0.0, 0.0,
01442                 0.0, 0.0, 1.0, 0.0,
01443                 0.0, 0.0, 0.0, 1.0;
01444     }
01445     else if (NCp==6)
01446     {
01447         IIsym = 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
01448                 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
01449                 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
01450                 0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
01451                 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
01452                 0.0, 0.0, 0.0, 0.0, 0.0, 1.0;
01453     }
01454     else throw new Fatal("matvec.h::Calc_IIsym: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01455 }
01456 
01458 inline void Calc_IdyI (size_t NCp, Mat_t & IdyI)
01459 {
01460     IdyI.change_dim(NCp,NCp);
01461     if (NCp==4)
01462     {
01463         IdyI = 1.0, 1.0, 1.0, 0.0,
01464                1.0, 1.0, 1.0, 0.0,
01465                1.0, 1.0, 1.0, 0.0,
01466                0.0, 0.0, 0.0, 0.0;
01467     }
01468     else if (NCp==6)
01469     {
01470         IdyI = 1.0, 1.0, 1.0, 0.0, 0.0, 0.0,
01471                1.0, 1.0, 1.0, 0.0, 0.0, 0.0,
01472                1.0, 1.0, 1.0, 0.0, 0.0, 0.0,
01473                0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
01474                0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
01475                0.0, 0.0, 0.0, 0.0, 0.0, 0.0;
01476     }
01477     else throw new Fatal("matvec.h::Calc_IdyI: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01478 }
01479 
01481 inline void Calc_Psd (size_t NCp, Mat_t & Psd)
01482 {
01483     Psd.change_dim(NCp,NCp);
01484     if (NCp==4)
01485     {
01486         Psd =  2.0/3.0, -1.0/3.0, -1.0/3.0, 0.0,
01487               -1.0/3.0,  2.0/3.0, -1.0/3.0, 0.0,
01488               -1.0/3.0, -1.0/3.0,  2.0/3.0, 0.0,
01489                    0.0,      0.0,      0.0, 1.0;
01490     }
01491     else if (NCp==6)
01492     {
01493         Psd =  2.0/3.0, -1.0/3.0, -1.0/3.0, 0.0, 0.0, 0.0,
01494               -1.0/3.0,  2.0/3.0, -1.0/3.0, 0.0, 0.0, 0.0,
01495               -1.0/3.0, -1.0/3.0,  2.0/3.0, 0.0, 0.0, 0.0,
01496                    0.0,      0.0,      0.0, 1.0, 0.0, 0.0,
01497                    0.0,      0.0,      0.0, 0.0, 1.0, 0.0,
01498                    0.0,      0.0,      0.0, 0.0, 0.0, 1.0;
01499     }
01500     else throw new Fatal("matvec.h::Calc_Psd: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01501 }
01502 
01504 inline void Calc_Piso (size_t NCp, Mat_t & Piso)
01505 {
01506     Piso.change_dim(NCp,NCp);
01507     if (NCp==4)
01508     {
01509         Piso = 1.0/3.0, 1.0/3.0, 1.0/3.0, 0.0,
01510                1.0/3.0, 1.0/3.0, 1.0/3.0, 0.0,
01511                1.0/3.0, 1.0/3.0, 1.0/3.0, 0.0,
01512                    0.0,     0.0,     0.0, 0.0;
01513     }
01514     else if (NCp==6)
01515     {
01516         Piso = 1.0/3.0, 1.0/3.0, 1.0/3.0, 0.0, 0.0, 0.0,
01517                1.0/3.0, 1.0/3.0, 1.0/3.0, 0.0, 0.0, 0.0,
01518                1.0/3.0, 1.0/3.0, 1.0/3.0, 0.0, 0.0, 0.0,
01519                    0.0,     0.0,     0.0, 0.0, 0.0, 0.0,
01520                    0.0,     0.0,     0.0, 0.0, 0.0, 0.0,
01521                    0.0,     0.0,     0.0, 0.0, 0.0, 0.0;
01522     }
01523     else throw new Fatal("matvec.h::Calc_Piso: This method is only available for 2nd order symmetric tensors with either 4 or 6 components according to Mandel's representation");
01524 }
01525 
01527 inline void EigenProjDerivs (Vec_t const & A, Vec3_t & L, Vec3_t & v0,   Vec3_t & v1,   Vec3_t & v2,
01528                                                           Vec_t &  P0,   Vec_t &  P1,   Vec_t &  P2,
01529                                                           Mat_t & dP0dA, Mat_t & dP1dA, Mat_t & dP2dA,
01530                              double Pertubation=1.0e-7, double Tol=1.0e-14, bool SortAsc=false, bool SortDesc=false)
01531 {
01532     // eigenprojectors
01533     EigenProj (A, L, v0, v1, v2, P0, P1, P2, SortAsc, SortDesc);
01534 
01535     // check eigenvalues
01536     if (fabs(L(0))<Tol) throw new Fatal("matvec.h::EigenProjDerivs: Principal values cannot be zero (Tol=%g).\n L = [%g, %g, %g]",Tol,L(0),L(1),L(2));
01537     if (fabs(L(1))<Tol) throw new Fatal("matvec.h::EigenProjDerivs: Principal values cannot be zero (Tol=%g).\n L = [%g, %g, %g]",Tol,L(0),L(1),L(2));
01538     if (fabs(L(2))<Tol) throw new Fatal("matvec.h::EigenProjDerivs: Principal values cannot be zero (Tol=%g).\n L = [%g, %g, %g]",Tol,L(0),L(1),L(2));
01539 
01540     // apply pertubation
01541     bool pert[3] = { false, false, false };
01542     if (fabs(L(0)-L(1))<Pertubation) { L(0)+=Pertubation;  L(1)-=Pertubation;  pert[0]=true; }
01543     if (fabs(L(1)-L(2))<Pertubation) { L(1)+=Pertubation;  L(2)-=Pertubation;  pert[1]=true; }
01544     if (fabs(L(2)-L(0))<Pertubation) { L(2)+=Pertubation;  L(0)-=Pertubation;  pert[2]=true; }
01545 
01546     // characteristic invariants
01547     double I1 = L(0)+L(1)+L(2);
01548     double I3 = L(0)*L(1)*L(2);
01549     double a[3] = {2.*L(0)*L(0)-I1*L(0)+I3/L(0),
01550                    2.*L(1)*L(1)-I1*L(1)+I3/L(1),
01551                    2.*L(2)*L(2)-I1*L(2)+I3/L(2)};
01552 
01553     // check alphas
01554     if (fabs(a[0])<Tol) throw new Fatal("matvec.h::EigenProjDerivs: Alpha0 cannot be zero (Tol=%g).\n  L = [%g, %g, %g]\n  I1,I3 = [%g, %g, %g]\n  Alphas = [%g, %g, %g]",Tol,L(0),L(1),L(2), I1,I3, a[0],a[1],a[2]);
01555     if (fabs(a[1])<Tol) throw new Fatal("matvec.h::EigenProjDerivs: Alpha1 cannot be zero (Tol=%g).\n  L = [%g, %g, %g]\n  I1,I3 = [%g, %g, %g]\n  Alphas = [%g, %g, %g]",Tol,L(0),L(1),L(2), I1,I3, a[0],a[1],a[2]);
01556     if (fabs(a[1])<Tol) throw new Fatal("matvec.h::EigenProjDerivs: Alpha2 cannot be zero (Tol=%g).\n  L = [%g, %g, %g]\n  I1,I3 = [%g, %g, %g]\n  Alphas = [%g, %g, %g]",Tol,L(0),L(1),L(2), I1,I3, a[0],a[1],a[2]);
01557 
01558     // inverse tensor and derivative of inverse
01559     size_t ncp = size(A);
01560     Vec_t Ai;
01561     Mat_t dInvAdA, IIsym;
01562     DerivInv   (A, Ai, dInvAdA, Tol);
01563     Calc_IIsym (ncp, IIsym);
01564 
01565     // dyadic between projectors
01566     Array<Mat_t> PdyP(3);
01567     Dyad (P0,P0, PdyP[0]);
01568     Dyad (P1,P1, PdyP[1]);
01569     Dyad (P2,P2, PdyP[2]);
01570 
01571     // constants
01572     double c[3][3] = {{I3/(a[0]*L(0)*L(0))-L(0)/a[0],  I3/(a[0]*L(1)*L(1))-L(0)/a[0],  I3/(a[0]*L(2)*L(2))-L(0)/a[0]},
01573                       {I3/(a[1]*L(0)*L(0))-L(1)/a[1],  I3/(a[1]*L(1)*L(1))-L(1)/a[1],  I3/(a[1]*L(2)*L(2))-L(1)/a[1]},
01574                       {I3/(a[2]*L(0)*L(0))-L(2)/a[2],  I3/(a[2]*L(1)*L(1))-L(2)/a[2],  I3/(a[2]*L(2)*L(2))-L(2)/a[2]}};
01575 
01576     // derivative of projector
01577     dP0dA.change_dim (ncp,ncp);
01578     dP1dA.change_dim (ncp,ncp);
01579     dP2dA.change_dim (ncp,ncp);
01580     dP0dA = (L(0)/a[0])*IIsym + (I3/a[0])*dInvAdA + c[0][0]*PdyP[0] + c[0][1]*PdyP[1] + c[0][2]*PdyP[2];
01581     dP1dA = (L(1)/a[1])*IIsym + (I3/a[1])*dInvAdA + c[1][0]*PdyP[0] + c[1][1]*PdyP[1] + c[1][2]*PdyP[2];
01582     dP2dA = (L(2)/a[2])*IIsym + (I3/a[2])*dInvAdA + c[2][0]*PdyP[0] + c[2][1]*PdyP[1] + c[2][2]*PdyP[2];
01583 
01584     // remove pertubation
01585     if (pert[0]) { L(0)-=Pertubation;  L(1)+=Pertubation; }
01586     if (pert[1]) { L(1)-=Pertubation;  L(2)+=Pertubation; }
01587     if (pert[2]) { L(2)-=Pertubation;  L(0)+=Pertubation; }
01588 }
01589 
01591 #ifdef HAS_TENSORS
01592 inline void EigenVecDerivs (Vec3_t const &  L, Ten1_t const &  v0,     Ten1_t const &  v1,     Ten1_t const &  v2,
01593                                                Ten3_t       & dv0dSig, Ten3_t       & dv1dSig, Ten3_t       & dv2dSig,
01594                             double Pertubation=1.0e-7, double Tol=1.0e-10)
01595 {
01596     // check eigenvalues
01597     if (fabs(L(0))<Tol) throw new Fatal("matvec.h::EigenVecDerivs: Principal values cannot be zero (Tol=%g).\n L = [%g, %g, %g]",Tol,L(0),L(1),L(2));
01598     if (fabs(L(1))<Tol) throw new Fatal("matvec.h::EigenVecDerivs: Principal values cannot be zero (Tol=%g).\n L = [%g, %g, %g]",Tol,L(0),L(1),L(2));
01599     if (fabs(L(2))<Tol) throw new Fatal("matvec.h::EigenVecDerivs: Principal values cannot be zero (Tol=%g).\n L = [%g, %g, %g]",Tol,L(0),L(1),L(2));
01600 
01601     // apply pertubation
01602     Vec3_t l(L);
01603     if (fabs(l(0)-l(1))<Pertubation) { l(0)+=Pertubation;  l(1)-=Pertubation; }
01604     if (fabs(l(1)-l(2))<Pertubation) { l(1)+=Pertubation;  l(2)-=Pertubation; }
01605     if (fabs(l(2)-l(0))<Pertubation) { l(2)+=Pertubation;  l(0)-=Pertubation; }
01606 
01607     // derivatives
01608     double a0 = 0.5/(l(0)-l(1));   double b0 = 0.5/(l(0)-l(2));
01609     double a1 = 0.5/(l(1)-l(2));   double b1 = 0.5/(l(1)-l(0));
01610     double a2 = 0.5/(l(2)-l(0));   double b2 = 0.5/(l(2)-l(1));
01611     dv0dSig = ((v1&v0&v1) + (v1&v1&v0))*a0  +  ((v2&v0&v2) + (v2&v2&v0))*b0;
01612     dv1dSig = ((v2&v1&v2) + (v2&v2&v1))*a1  +  ((v0&v1&v0) + (v0&v0&v1))*b1;
01613     dv2dSig = ((v0&v2&v0) + (v0&v0&v2))*a2  +  ((v1&v2&v1) + (v1&v1&v2))*b2;
01614 }
01615 #endif
01616 
01617 
01619 
01620 
01621 // Cambridge invariants
01622 inline double Calc_pcam  (Vec_t const & Sig) { return -(Sig(0)+Sig(1)+Sig(2))/3.0; }
01623 inline double Calc_ev    (Vec_t const & Eps) { return   Eps(0)+Eps(1)+Eps(2);      }
01624 inline double Calc_qcam  (Vec_t const & Sig) { double m = (size(Sig)>4 ? pow(Sig(4),2.0)+pow(Sig(5),2.0) : 0.0); return sqrt(pow(Sig(0)-Sig(1),2.0) + pow(Sig(1)-Sig(2),2.0) + pow(Sig(2)-Sig(0),2.0) + 3.0*(pow(Sig(3),2.0)+m))/sqrt(2.0); }
01625 inline double Calc_ed    (Vec_t const & Eps) { double m = (size(Eps)>4 ? pow(Eps(4),2.0)+pow(Eps(5),2.0) : 0.0); return sqrt(pow(Eps(0)-Eps(1),2.0) + pow(Eps(1)-Eps(2),2.0) + pow(Eps(2)-Eps(0),2.0) + 3.0*(pow(Eps(3),2.0)+m))*(sqrt(2.0)/3.0); }
01626 
01627 // Octahedral invariants
01628 inline double Calc_poct  (Vec_t const & Sig) { return -(Sig(0)+Sig(1)+Sig(2))/sqrt(3.0); }
01629 inline double Calc_evoct (Vec_t const & Eps) { return  (Eps(0)+Eps(1)+Eps(2))/sqrt(3.0); }
01630 inline double Calc_qoct  (Vec_t const & Sig) { double m = (size(Sig)>4 ? pow(Sig(4),2.0)+pow(Sig(5),2.0) : 0.0); return sqrt(pow(Sig(0)-Sig(1),2.0) + pow(Sig(1)-Sig(2),2.0) + pow(Sig(2)-Sig(0),2.0) + 3.0*(pow(Sig(3),2.0)+m))/sqrt(3.0); }
01631 inline double Calc_edoct (Vec_t const & Eps) { double m = (size(Eps)>4 ? pow(Eps(4),2.0)+pow(Eps(5),2.0) : 0.0); return sqrt(pow(Eps(0)-Eps(1),2.0) + pow(Eps(1)-Eps(2),2.0) + pow(Eps(2)-Eps(0),2.0) + 3.0*(pow(Eps(3),2.0)+m))/sqrt(3.0); }
01632 
01633 // Octahedral invariants of Sig. */
01634 inline void Calc_pqoct (Vec_t const & Sig, double & p, double & q) { p = Calc_poct(Sig);  q = Calc_qoct(Sig); }
01635 
01636 
01638 inline void OctInvs (Vec_t const & Sig, double & p, double & q, double & t, double qTol=1.0e-8)
01639 {
01640     size_t ncp = size(Sig);
01641     Vec_t s;
01642     Dev (Sig, s);
01643     double m = (ncp>4 ? pow(Sig(4),2.0)+pow(Sig(5),2.0) : 0.0);
01644     p = -(Sig(0)+Sig(1)+Sig(2))/Util::SQ3;
01645     q = sqrt(pow(Sig(0)-Sig(1),2.0) + pow(Sig(1)-Sig(2),2.0) + pow(Sig(2)-Sig(0),2.0) + 3.0*(pow(Sig(3),2.0)+m))/sqrt(3.0);
01646     t = 0.0;
01647     if (q>qTol)
01648     {
01649         double det_s = Det(s);
01650         t = -3.0*Util::SQ6*det_s/(q*q*q);
01651         if (t<=-1.0) t = -1.0;
01652         if (t>= 1.0) t =  1.0;
01653     }
01654 }
01655 
01657 inline void OctInvs (Vec_t const & Sig, double & p, double & q, Vec_t & s, double qTol=1.0e-8, bool ApplyPertub=false)
01658 {
01659     q = Calc_qoct (Sig);
01660     if (q>qTol || !ApplyPertub)
01661     {
01662         p = Calc_poct (Sig);
01663         Dev (Sig, s);
01664     }
01665     else
01666     {
01667         Vec_t sig(Sig);
01668         if (sig(3)<0.0) sig(3) -= qTol*Util::SQ2;
01669         else            sig(3) += qTol*Util::SQ2;
01670         q = Calc_qoct (sig);
01671         p = Calc_poct (sig);
01672         Dev (sig, s);
01673         if (q<=qTol)
01674         {
01675             std::ostringstream oss;
01676             oss << "Sig = " << PrintVector(Sig);
01677             oss << "sig = " << PrintVector(sig);
01678             throw new Fatal("matvec.h::OctInvs: __internal_error__ Pertubation for q<=qTol failed (q=%g, qTol=%g)\n%s",q,qTol,oss.str().c_str());
01679         }
01680     }
01681 }
01682 
01684 inline void OctInvs (Vec_t const & Sig, double & p, double & q, double & t, double & th, Vec_t & s, double qTol=1.0e-8, Vec_t * dthdSig=NULL, bool ApplyPertub=false)
01685 {
01686     OctInvs (Sig, p, q, s, qTol, ApplyPertub);
01687     t  = 0.0;
01688     th = asin(t)/3.0;
01689     double q3 = pow(q,3.0);
01690     if (q3>qTol)
01691     {
01692         double det_s = Det(s);
01693         t = -3.0*Util::SQ6*det_s/q3;
01694         if (t<=-1.0) t = -1.0;
01695         if (t>= 1.0) t =  1.0;
01696         th = asin(t)/3.0;
01697         if (dthdSig!=NULL)
01698         {
01699             Vec_t ss, devss;
01700             Pow2 (s, ss);
01701             Dev  (ss, devss);
01702             if (t>-0.999 && t<0.999) (*dthdSig) = (-1.0/(q*q*cos(3.0*th)))*(t*s + (Util::SQ6/q)*devss);
01703             else set_to_zero ((*dthdSig));
01704         }
01705     }
01706     else if (dthdSig!=NULL) set_to_zero ((*dthdSig));
01707 }
01708 
01710 inline void OctInvs (Vec3_t const & L, double & p, double & q, double & t, double qTol=1.0e-8)
01711 {
01712     p = -(L(0)+L(1)+L(2))/Util::SQ3;
01713     q = sqrt(pow(L(0)-L(1),2.0) + pow(L(1)-L(2),2.0) + pow(L(2)-L(0),2.0))/sqrt(3.0);
01714     t = 0.0;
01715     if (q>qTol)
01716     {
01717         Vec3_t S((2.*L(0)-L(1)-L(2))/3.,
01718                  (2.*L(1)-L(2)-L(0))/3.,
01719                  (2.*L(2)-L(0)-L(1))/3.);
01720         t = -3.0*Util::SQ6*S(0)*S(1)*S(2)/pow(q,3.0);
01721         if (t<=-1.0) t = -1.0;
01722         if (t>= 1.0) t =  1.0;
01723     }
01724 }
01725 
01727 inline void OctInvs (Vec3_t const & L, double & p, double & q, double & t, Vec3_t & dpdL, Vec3_t & dqdL, Vec3_t & dtdL, double qTol=1.0e-8)
01728 {
01729     Vec3_t one(1.0,1.0,1.0), s;
01730     p    = -(L(0)+L(1)+L(2))/Util::SQ3;
01731     q    = sqrt(pow(L(0)-L(1),2.0) + pow(L(1)-L(2),2.0) + pow(L(2)-L(0),2.0))/sqrt(3.0);
01732     t    = 0.0;
01733     s    = L - ((L(0)+L(1)+L(2))/3.0)*one;
01734     dpdL = (-1.0/Util::SQ3)*one;
01735     dqdL = 0.0, 0.0, 0.0;
01736     if (q>qTol)
01737     {
01738         double q3 = q*q*q;
01739         double q5 = q3*q*q;
01740         double l  = (L(0)-L(1))*(L(1)-L(2))*(L(2)-L(0));
01741         Vec3_t B(L(2)-L(1), L(0)-L(2), L(1)-L(0));
01742         t    = -3.0*Util::SQ6*s(0)*s(1)*s(2)/q3;
01743         dqdL = (1.0/q)*s;
01744         dtdL = (-Util::SQ6*l/q5)*B;
01745         if (t<=-1.0) t = -1.0;
01746         if (t>= 1.0) t =  1.0;
01747     }
01748 }
01749 
01751 inline void pqth2L (double p, double q, double th, Vec3_t & L, char const * Type="oct")
01752 {
01753     if (strcmp(Type,"cam")==0)
01754     {
01755         L(0) = -p + 2.0*q*sin(th-2.0*Util::PI/3.0)/3.0;
01756         L(1) = -p + 2.0*q*sin(th)                 /3.0;
01757         L(2) = -p + 2.0*q*sin(th+2.0*Util::PI/3.0)/3.0;
01758     }
01759     else if (strcmp(Type,"oct")==0) // oct
01760     {
01761         L(0) = -p/Util::SQ3 + 2.0*q*sin(th-2.0*Util::PI/3.0)/Util::SQ6;
01762         L(1) = -p/Util::SQ3 + 2.0*q*sin(th)                 /Util::SQ6;
01763         L(2) = -p/Util::SQ3 + 2.0*q*sin(th+2.0*Util::PI/3.0)/Util::SQ6;
01764     }
01765     else throw new Fatal("pqTh2L: Method is not available for invariant Type==%s",Type);
01766 }
01767 
01768 inline void OctDerivs (Vec3_t const & L, double & p, double & q, double & t, Mat3_t & dpqthdL, double qTol=1.0e-8)
01769 {
01770     OctInvs (L, p,q,t, qTol);
01771     if (q>qTol)
01772     {
01773 
01774         Vec3_t S((2.*L(0)-L(1)-L(2))/3., 
01775                  (2.*L(1)-L(2)-L(0))/3.,
01776                  (2.*L(2)-L(0)-L(1))/3.);
01777         Vec3_t devSS((2.*S(1)*S(2) - S(2)*S(0) - S(0)*S(1))/3.,
01778                      (2.*S(2)*S(0) - S(1)*S(2) - S(0)*S(1))/3.,
01779                      (2.*S(0)*S(1) - S(1)*S(2) - S(2)*S(0))/3.);
01780         double th = asin(t)/3.0;
01781         double c  = -1.0/(pow(q,3.0)*cos(3.0*th));
01782         dpqthdL = -1./Util::SQ3,                   -1./Util::SQ3,                   -1./Util::SQ3,
01783                   S(0)/q,                          S(1)/q,                          S(2)/q,
01784                   c*Util::SQ6*devSS(0)+c*q*t*S(0), c*Util::SQ6*devSS(1)+c*q*t*S(1), c*Util::SQ6*devSS(2)+c*q*t*S(2);
01785     }
01786     else
01787     {
01788         dpqthdL = -1./Util::SQ3, -1./Util::SQ3, -1./Util::SQ3,
01789                    0.,            0.,            0.,
01790                    0.,            0.,            0.;
01791     }
01792 }
01793 
01794 inline void InvOctDerivs (Vec3_t const & Lsorted, double & p, double & q, double & t, Mat3_t & dLdpqth, double qTol=1.0e-8)
01795 {
01796     OctInvs (Lsorted, p,q,t, qTol);
01797     double th = asin(t)/3.0;
01798     dLdpqth = -1./Util::SQ3, (2.*sin(th-(2.*Util::PI)/3.))/Util::SQ6, (2.*q*cos(th-(2.*Util::PI)/3.))/Util::SQ6,
01799               -1./Util::SQ3, (2.*sin(th)                 )/Util::SQ6, (2.*q*cos(th)                 )/Util::SQ6,
01800               -1./Util::SQ3, (2.*sin(th+(2.*Util::PI)/3.))/Util::SQ6, (2.*q*cos(th+(2.*Util::PI)/3.))/Util::SQ6;
01801 }
01802 
01803 #ifdef USE_BOOST_PYTHON
01804 inline BPy::tuple Pypqth2L (double p, double q, double th, BPy::str const & Type)
01805 {
01806     Vec3_t l;
01807     pqth2L (p, q, th, l, BPy::extract<char const *>(Type)());
01808     return BPy::make_tuple (l(0), l(1), l(2));
01809 }
01810 #endif
01811 
01812 
01814 
01815 
01817 inline double Phi2M (double Phi, char const * Type="oct")
01818 {
01819     double sphi = sin(Phi*Util::PI/180.0);
01820     if      (strcmp(Type,"oct")==0) return 2.0*Util::SQ2*sphi/(3.0-sphi);
01821     else if (strcmp(Type,"cam")==0) return 6.0*sphi/(3.0-sphi);
01822     else if (strcmp(Type,"smp")==0)
01823     {
01824         double eta = 2.0*Util::SQ2*sphi/(3.0-sphi);
01825         double c   = sqrt((2.0+Util::SQ2*eta-2.0*eta*eta)/(3.0*Util::SQ3*(Util::SQ2*eta+2.0)));
01826         double a   = sqrt((2.0*eta+Util::SQ2)/Util::SQ6);
01827         double b   = sqrt((Util::SQ2-eta)/Util::SQ6);
01828         return sqrt((eta*eta+1.0)/(c*c*pow(a+2.0*b,2.0))-1.0);
01829     }
01830     else throw new Fatal("Phi2M: Method is not available for invariant Type==%s",Type);
01831 }
01832 
01834 inline double M2Phi (double M, char const * Type="oct")
01835 {
01836     double sphi;
01837     if      (strcmp(Type,"oct")==0) sphi = 3.0*M/(M+2.0*Util::SQ2);
01838     else if (strcmp(Type,"cam")==0) sphi = 3.0*M/(M+6.0);
01839     else throw new Fatal("M2Phi: Method is not available for invariant Type==%s",Type);
01840     return asin(sphi)*180.0/Util::PI;
01841 }
01842 
01844 inline double Calc_K (double E, double nu) { return E/(3.0*(1.0-2.0*nu)); }
01845 
01847 inline double Calc_G (double E, double nu) { return E/(2.0*(1.0+nu)); }
01848 
01850 inline double Calc_lam (double E, double nu) { return E*nu/((1.0+nu)*(1.0-2.0*nu)); }
01851 
01853 inline double Calc_G_ (double K, double nu) { return 3.0*(1.0-2.0*nu)*K/(2.0*(1.0+nu)); }
01854 
01856 inline double Calc_E (double K, double G) { return 9.0*K*G/(3.0*K+G); }
01857 
01859 inline double Calc_E_ (double K, double nu) { return 3.0*K*(1.0-2.0*nu); }
01860 
01862 inline double Calc_nu (double K, double G) { return (3.0*K-2.0*G)/(6.0*K+2.0*G); }
01863 
01864 
01866 
01867 
01868 #ifdef USE_BOOST_PYTHON
01869 
01870 inline void Vec2List (Vec3_t const & V, BPy::list & L)
01871 {
01872     for (size_t i=0; i<3; ++i) L.append(V(i));
01873 }
01874 
01875 inline void Vec2List (Vec_t const & V, BPy::list & L)
01876 {
01877     for (size_t i=0; i<size(V); ++i) L.append(V(i));
01878 }
01879 
01880 inline void List2Vec (BPy::list const & L, Vec_t & V)
01881 {
01882     size_t m = BPy::len(L);
01883     if (m>0)
01884     {
01885         V.change_dim (m);
01886         for (size_t i=0; i<m; ++i) V(i) = BPy::extract<double>(L[i])();
01887     }
01888 }
01889 
01890 inline void Mat2List (Mat_t const & M, BPy::list & L)
01891 {
01892     size_t m = num_rows(M);
01893     size_t n = num_cols(M);
01894     for (size_t i=0; i<m; ++i)
01895     {
01896         BPy::list row;
01897         for (size_t j=0; j<n; ++j) row.append(M(i,j));
01898         L.append(row);
01899     }
01900 }
01901 
01902 inline void List2Mat (BPy::list const & L, Mat_t & M)
01903 {
01904     size_t m = BPy::len(L);
01905     if (m>0)
01906     {
01907         size_t n = BPy::len(BPy::extract<BPy::list>(L[0])());
01908         M.change_dim (m,n);
01909         for (size_t i=0; i<m; ++i)
01910         {
01911             BPy::list const & row = BPy::extract<BPy::list>(L[i])();
01912             for (size_t j=0; j<n; ++j) M(i,j) = BPy::extract<double>(row[j])();
01913         }
01914     }
01915 }
01916 
01917 inline void PyEigenProjAnalytic (BPy::list const & Ten, BPy::list & L, BPy::list & P0, BPy::list & P1, BPy::list & P2)
01918 {
01919     Vec3_t l;
01920     Vec_t  ten, p0, p1, p2;
01921     List2Vec          (Ten, ten);
01922     EigenProjAnalytic (ten, l, p0, p1, p2);
01923     Vec2List          (l, L);
01924     Vec2List          (p0, P0);
01925     Vec2List          (p1, P1);
01926     Vec2List          (p2, P2);
01927 }
01928 
01929 #endif
01930 
01931 #endif // MECHSYS_MATVEC_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines