diff --git a/Numeric/EigenSolve3x3.cpp b/Numeric/EigSolve.cpp similarity index 89% rename from Numeric/EigenSolve3x3.cpp rename to Numeric/EigSolve.cpp index 94c3ad34b685cc8f98238ecacadc046d5e0a48cf..7ebba60fc8b85910997b93d412ec233cf0e9b53d 100644 --- a/Numeric/EigenSolve3x3.cpp +++ b/Numeric/EigSolve.cpp @@ -1,4 +1,4 @@ -// $Id: EigenSolve3x3.cpp,v 1.1 2004-12-08 03:09:03 geuzaine Exp $ +// $Id: EigSolve.cpp,v 1.1 2004-12-08 05:38:56 geuzaine Exp $ // // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle // @@ -21,8 +21,8 @@ // This file contains a routine that numerically finds the eigenvalues // and eigenvectors of a N X N Real Matrix. It is a C++ translation of -// a Javascript translation of a routine from EISPACK. The Javascript -// implementation comes from http://www.akiti.ca/Eig3Solv.html. +// a Javascript translation of Fortran routines from EISPACK. The +// Javascript implementation comes from http://www.akiti.ca/Eig3Solv.html // // References: // @@ -37,13 +37,6 @@ // Springer-Verlag, Berlin. // 1977 // -// The original sub-routines were written in FORTRAN and have been -// translated to Javascript here. Although all care has been taken to -// ensure that the sub-routines were translated accurately, some -// errors may have crept into the translation. These errors are mine; -// the original FORTRAN routines have been thoroughly tested and work -// properly. Please report any errors to the webmaster. -// // IMPORTANT! How to use the output: // // If the i-th eigenvalue is real, the i-th COLUMN of the eigenvector @@ -60,10 +53,8 @@ #include "Gmsh.h" #include "Numeric.h" -#define N 3 //Global variable, dimension of matrix. - -static void cdivA(double ar, double ai, double br, double bi, - double A[N][N], int in1, int in2, int in3) +static void cdivA(int N, double ar, double ai, double br, double bi, + double **A, int in1, int in2, int in3) { // Division routine for dividing one complex number into another: // This routine does (ar + ai)/(br + bi) and returns the results in @@ -82,8 +73,8 @@ static void cdivA(double ar, double ai, double br, double bi, return; } // End cdivA -static void hqr2(double A[N][N], double B[N][N], int low, int igh, - double wi[N], double wr[N], int ierr) +static void hqr2(int N, double **A, double **B, int low, int igh, + double *wi, double *wr, int ierr) { // Computes the eigenvalues and eigenvectors of a real // upper-Hessenberg Matrix using the QR method. @@ -391,7 +382,7 @@ static void hqr2(double A[N][N], double B[N][N], int low, int igh, m = na; if (fabs(A[en][na]) <= fabs(A[na][en])) - cdivA(0.0, -A[na][en], -p + A[na][na], q, A, na, na, en); + cdivA(N, 0.0, -A[na][en], -p + A[na][na], q, A, na, na, en); else { A[na][na] = q/A[en][na]; A[na][en] = -(-p + A[en][en])/A[en][na]; @@ -419,7 +410,7 @@ static void hqr2(double A[N][N], double B[N][N], int low, int igh, //else wi[j] >= 0.0 m = j; if (wi[j] == 0.0) - cdivA(-ra, -sa, w, q, A, j, na, en); + cdivA(N, -ra, -sa, w, q, A, j, na, en); else {//wi[j] > 0.0; solve complex equations x = A[j][j + 1]; y = A[j + 1][j]; @@ -433,14 +424,14 @@ static void hqr2(double A[N][N], double B[N][N], int low, int igh, tst2 = tst1 + vr; } while (tst2 > tst1); } //End if vr and vi == 0.0 - cdivA(-(zz*ra) + x*r + q*sa, -(zz*sa + q*ra) + x*s, vr, vi, A, j, na, en); + cdivA(N, -(zz*ra) + x*r + q*sa, -(zz*sa + q*ra) + x*s, vr, vi, A, j, na, en); if (fabs(x) > (fabs(zz) + fabs(q))){ A[j + 1][na] = (-(ra + w*A[j][na]) + q*A[j][en])/x; A[j + 1][en] = -(sa + w*A[j][en] + q*A[j][na])/x; }//End if else - cdivA(-(r + y*A[j][na]), -(s + y*A[j][en]), zz, q, A, j + 1, na, en); + cdivA(N, -(r + y*A[j][na]), -(s + y*A[j][en]), zz, q, A, j + 1, na, en); }//End else wi[j] > 0.0 @@ -492,7 +483,7 @@ static void hqr2(double A[N][N], double B[N][N], int low, int igh, return; } //End of function hqr2 -static void norVecC(double Z[N][N], double wi[N]) +static void norVecC(int N, double **Z, double *wi) { // Normalizes the eigenvectors @@ -559,14 +550,14 @@ static void norVecC(double Z[N][N], double wi[N]) return; } // End norVecC -static void swap_elements(double v[N], int i, int k) +static void swap_elements(int N, double *v, int i, int k) { double tmp = v[k]; v[k] = v[i]; v[i] = tmp; } -static void swap_columns(double v[N][N], int i, int k) +static void swap_columns(int N, double **v, int i, int k) { for(int n = 0; n < N; n++){ double tmp = v[n][k]; @@ -575,7 +566,7 @@ static void swap_columns(double v[N][N], int i, int k) } } -void EigenSort3x3(double wr[N], double wi[N], double B[N][N]) +void EigSort(int N, double *wr, double *wi, double **B) { for (int i = 0; i < N - 1; i++){ int k = i; @@ -589,20 +580,29 @@ void EigenSort3x3(double wr[N], double wi[N], double B[N][N]) } } if (k != i){ - swap_elements (wr, i, k); - swap_elements (wi, i, k); - swap_columns (B, i, k); + swap_elements(N, wr, i, k); + swap_elements(N, wi, i, k); + swap_columns(N, B, i, k); } } } -int EigenSolve3x3(double A[N][N], double wr[N], double wi[N], double B[N][N]) +int EigSolve(int N, double **A, double *wr, double *wi, double **B, + int *itmp, double *dtmp) { - // Balance the matrix to improve accuracy of eigenvalues. Introduces - // no rounding errors, since it scales A by powers of the radix. + // Computes the N eigenvalues of the square, real matrix A. All + // vectors have dimension N and all matrices have dimension + // NxN. Warning: the matrix A gets modified during the + // computation. The eigenvalues/vectors are sorted in ascending + // order according to the real part of the eigenvalues. + + // Balance the matrix to improve accuracy of + // eigenvalues. (Introduces no rounding errors, since it scales A by + // powers of the radix.) + + double *scale = dtmp; //Contains information about transformations. + int *trace = itmp; //Records row and column interchanges - double scale[N]; //Contains information about transformations. - int trace[N]; //Records row and column interchanges double radix = 2; //Base of machine floating point representation. double c, f, g, r, s, b2 = radix*radix; int ierr = -1, igh, low, k = 0, l = N - 1, noconv; @@ -814,7 +814,7 @@ int EigenSolve3x3(double A[N][N], double wr[N], double wi[N], double B[N][N]) } // End for i - hqr2(A, B, low, igh, wi, wr, ierr); + hqr2(N, A, B, low, igh, wi, wr, ierr); if (ierr == -1){ @@ -848,22 +848,35 @@ int EigenSolve3x3(double A[N][N], double wr[N], double wi[N], double B[N][N]) }//End if k != i }//End for i - norVecC(B, wi); //Normalize the eigenvectors + norVecC(N, B, wi); //Normalize the eigenvectors }//End if ierr = -1 - - EigenSort3x3(wr, wi, B); + EigSort(N, wr, wi, B); + return ierr; } //End of Eig3Solve # if 0 int main() { - double wr[3], wi[3], B[3][3]; + const int N = 3; + double *wr = new double[N]; + double *wi = new double[N]; + double **A = new double*[N]; + double **B = new double*[N]; + for(int i = 0; i < N; i++){ + A[i] = new double[N]; + B[i] = new double[N]; + } + double *dtmp = new double[N]; + int *itmp = new int[N]; + for(int i = 0; i < 1000000; i++){ // perf test - double A[3][3] = { {1.,2.,3.}, {2.,4.,5.}, {3.,5.,6.} }; - EigenSolve3x3(A, wr, wi, B); + A[0][0] = 1.; A[0][1] = 2.; A[0][2] = 3.; + A[1][0] = 2.; A[1][1] = 4.; A[1][2] = 5.; + A[2][0] = 3.; A[2][1] = 5.; A[2][2] = 6.; + EigSolve(3, A, wr, wi, B, itmp, dtmp); } /* printf("%g %g %g\n", A[0][0], A[0][1], A[0][2]); diff --git a/Numeric/Makefile b/Numeric/Makefile index 216ffd20f9a6cc32459db3dc930477aa8172fe4c..66720267cd065dd8f6b1ffa9614cf7d8c259e4f3 100644 --- a/Numeric/Makefile +++ b/Numeric/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.15 2004-12-08 03:09:03 geuzaine Exp $ +# $Id: Makefile,v 1.16 2004-12-08 05:38:56 geuzaine Exp $ # # Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle # @@ -26,7 +26,7 @@ INCLUDE = -I../Common -I../DataStr CFLAGS = ${OPTIM} ${FLAGS} ${INCLUDE} SRC = Numeric.cpp\ - EigenSolve3x3.cpp\ + EigSolve.cpp\ gsl_newt.cpp\ gsl_brent.cpp @@ -56,7 +56,7 @@ depend: Numeric.o: Numeric.cpp ../Common/Gmsh.h ../Common/Message.h \ ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \ ../DataStr/avl.h ../DataStr/Tools.h Numeric.h -EigenSolve3x3.o: EigenSolve3x3.cpp ../Common/Gmsh.h ../Common/Message.h \ +EigSolve.o: EigSolve.cpp ../Common/Gmsh.h ../Common/Message.h \ ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \ ../DataStr/avl.h ../DataStr/Tools.h Numeric.h gsl_newt.o: gsl_newt.cpp ../Common/Gmsh.h ../Common/Message.h \ diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h index b8ec30a44f0a6e8dee9e406885fdc10a4e398f2d..54953f998b96ee2fd05e97bb00e4846ce45819db 100644 --- a/Numeric/Numeric.h +++ b/Numeric/Numeric.h @@ -73,7 +73,8 @@ double angle_02pi(double A3); void eigenvalue(double mat[3][3], double re[3]); void FindCubicRoots(const double coeff[4], double re[3], double im[3]); void eigsort(double d[3]); -int EigenSolve3x3(double A[3][3], double wr[3], double wi[3], double B[3][3]); +int EigSolve(int N, double **A, double *wr, double *wi, double **B, + int *itmp, double *dtmp); double InterpolateIso(double *X, double *Y, double *Z, double *Val, double V, int I1, int I2, diff --git a/Plugin/PrincipalStresses.cpp b/Plugin/PrincipalStresses.cpp index e42f81b1bec041e6fc8ac402dc79ee27badf9648..3d4bf7653cddfc76f2c00e9ac21a7e352d7570dd 100644 --- a/Plugin/PrincipalStresses.cpp +++ b/Plugin/PrincipalStresses.cpp @@ -1,4 +1,4 @@ -// $Id: PrincipalStresses.cpp,v 1.1 2004-12-08 03:10:06 geuzaine Exp $ +// $Id: PrincipalStresses.cpp,v 1.2 2004-12-08 05:38:56 geuzaine Exp $ // // Copyright (C) 1997-2004 C. Geuzaine, J.-F. Remacle // @@ -92,7 +92,15 @@ static void principal_stresses(List_T *inList, int inNb, int nbNod, int nbTime, List_T *midList, int *midNb, List_T *maxList, int *maxNb) { - int nbcomplex = 0; + int itmp[3], nbcomplex = 0; + double wr[3], wi[3], dtmp[3]; + double **A = new double*[3]; + double **B = new double*[3]; + for(int i = 0; i < 3; i++){ + A[i] = new double[3]; + B[i] = new double[3]; + } + int nb = List_Nbr(inList) / inNb; for(int i = 0; i < List_Nbr(inList); i += nb) { for(int j = 0; j < 3 * nbNod; j++){ @@ -104,11 +112,10 @@ static void principal_stresses(List_T *inList, int inNb, int nbNod, int nbTime, for(int k = 0; k < nbNod; k++){ double *val = (double *)List_Pointer_Fast(inList, i + 3 * nbNod + nbNod * 9 * j + 9 * k); - double A[3][3] = { {val[0], val[1], val[2]}, - {val[3], val[4], val[5]}, - {val[6], val[7], val[8]} }; - double wr[3], wi[3], B[3][3]; - EigenSolve3x3(A, wr, wi, B); + A[0][0] = val[0]; A[0][1] = val[1]; A[0][2] = val[2]; + A[1][0] = val[3]; A[1][1] = val[4]; A[1][2] = val[5]; + A[2][0] = val[6]; A[2][1] = val[7]; A[2][2] = val[8]; + EigSolve(3, A, wr, wi, B, itmp, dtmp); nbcomplex += nonzero(wi); //printf("djf=%g %g %g\n", wr[0], wr[1], wr[2]); //printf("vec1=%g %g %g\n", B[0][0], B[1][0], B[2][0]); @@ -117,7 +124,7 @@ static void principal_stresses(List_T *inList, int inNb, int nbNod, int nbTime, for(int l = 0; l < 3; l++){ double res; // wrong if there are complex eigenvals (B contains both - // real and imag parts: cf. explanation in EigenSolve3x3) + // real and imag parts: cf. explanation in EigSolve.cpp) res = wr[0] * B[l][0]; List_Add(minList, &res); res = wr[1] * B[l][1]; List_Add(midList, &res); res = wr[2] * B[l][2]; List_Add(maxList, &res); @@ -129,6 +136,13 @@ static void principal_stresses(List_T *inList, int inNb, int nbNod, int nbTime, (*maxNb)++; } + for(int i = 0; i < 3; i++){ + delete [] A[i]; + delete [] B[i]; + } + delete [] A; + delete [] B; + if(nbcomplex) Msg(GERROR, "%d elements have complex eigenvalues/eigenvectors"); }