/****************************************************************************** * * ELMER, A Computational Fluid Dynamics Program. * * Copyright 1st April 1995 - , Center for Scientific Computing, * Finland. * * All rights reserved. No part of this program may be used, * reproduced or transmitted in any form or by any means * without the written permission of CSC. * ******************************************************************************/ /******************************************************************************* * * Solve symmetric positive definite eigenvalue problem. * ******************************************************************************* * * Author: Juha Ruokolainen * * Address: Center for Scientific Computing * Tietotie 6, P.O. BOX 405 * 02101 Espoo, Finland * Tel. +358 0 457 2723 * Telefax: +358 0 457 2302 * EMail: Juha.Ruokolainen@csc.fi * * Date: 30 May 1996 * * Modified by: * * Date of modification: * ******************************************************************************/ /* * $Id: jacobi.c,v 1.1.1.1 2005/04/14 13:29:14 vierinen Exp $ * * $Log: jacobi.c,v $ * Revision 1.1.1.1 2005/04/14 13:29:14 vierinen * initial matc automake package * * Revision 1.2 1998/08/01 12:34:43 jpr * * Added Id, started Log. * * */ #include "elmer/matc.h" VARIABLE *mtr_jacob(a) VARIABLE *a; { VARIABLE *x, *ev; double *b, *d, rtol; int i, n; if (NROW(a) != NCOL(a)) error("Jacob: Matrix must be square.\n"); b = MATR(NEXT(a)); n = NROW(a); if (NROW(NEXT(a)) != NCOL(NEXT(a)) || n != NROW(NEXT(a))) error("Jacob: Matrix dimensions incompatible.\n"); rtol = *MATR(NEXT(NEXT(a))); x = var_new("eigv", TYPE_DOUBLE, NROW(a), NCOL(a)); d = (double *)ALLOCMEM(n * sizeof(double)); ev = var_temp_new(TYPE_DOUBLE, 1, n); jacobi(MATR(a), b, MATR(x), MATR(ev), d, n, rtol); FREEMEM((char *)d); return ev; }; /************************************************************************ P R O G R A M To solve the generalized eigenproblem using the generalized Jacobi iteration INPUT a(n,n) = Stiffness matrix (assumed positive definite) b(n,n) = Mass matrix (assumed positive definite) x(n,n) = Matrix storing eigenvectors on solution exit eigv(n) = Vector storing eigenvalues on solution exit d(n) = Working vector n = Order of the matrices a and b rtol = Convergence tolerance (usually set to 10.**-12) nsmax = Maximum number of sweeps allowed (usually set to 15) OUTPUT a(n,n) = Diagonalized stiffness matrix b(n,n) = Diagonalized mass matrix x(n,n) = Eigenvectors stored columnwise eigv(n) = Eigenvalues *************************************************************************/ int jacobi(a,b,x,eigv,d,n,rtol) double a[],b[],x[],eigv[],d[],rtol; int n; { register int i,j,k,ii,jj; int nsmax=50, /* Max number of sweeps */ nsweep, /* Current sweep number */ nr, jp1,jm1,kp1,km1, convergence; double eps, eptola,eptolb, akk,ajj,ab, check,sqch, d1,d2,den, ca,cg, aj,bj,ak,bk, xj,xk, tol,dif, epsa,epsb, bb; /* Scale mass matrix */ /************************************************************************ Initialize eigenvalue and eigenvector matrices *************************************************************************/ for( i=0 ; i= eps || eptolb >=eps ) { /************************************************************************ if zeroing is required, calculate the rotation matrix elements *************************************************************************/ akk=a[k*n+k]*b[j*n+k] - b[k*n+k]*a[j*n+k]; ajj=a[j*n+j]*b[j*n+k] - b[j*n+j]*a[j*n+k]; ab =a[j*n+j]*b[k*n+k] - a[k*n+k]*b[j*n+j]; check=(ab*ab+4.0*akk*ajj)/4.0; if (check<=0.0) { printf("***Error solution stop in *jacobi*\n"); printf(" check = %20.14e\n", check); return 1; } sqch= sqrt(check); d1 = ab/2.0+sqch; d2 = ab/2.0-sqch; den = d1; if ( abs(d2) > abs(d1) ) den=d2; if (den == 0.0) { ca=0.0; cg= -a[j*n+k] / a[k*n+k]; } else { ca= akk/den; cg= -ajj/den; } /************************************************************************ Perform the generalized rotation to zero the present off-diagonal element *************************************************************************/ if (n != 2) { jp1=j+1; jm1=j-1; kp1=k+1; km1=k-1; /**************************************/ if ( jm1 >= 0) for (i=0 ; i<=jm1 ; i++) { aj = a[i*n+j]; bj = b[i*n+j]; ak = a[i*n+k]; bk = b[i*n+k]; a[i*n+j] = aj+cg*ak; b[i*n+j] = bj+cg*bk; a[i*n+k] = ak+ca*aj; b[i*n+k] = bk+ca*bj; }; /**************************************/ if ((kp1-n+1) <= 0) for (i=kp1 ; i tol) convergence = 0; if (! convergence) break; }; /************************************************************************ check if all off-diag elements are satisfactorily small *************************************************************************/ if (convergence) { eps=rtol*rtol; for (j=0 ; j= eps || epsb >=eps ) convergence = 0; if (! convergence) break; }; if (! convergence) break; }; }; if (! convergence) { for (i=0 ; i