/*****************************************************************************1*2* Elmer, A Finite Element Software for Multiphysical Problems3*4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland5*6* This library is free software; you can redistribute it and/or7* modify it under the terms of the GNU Lesser General Public8* License as published by the Free Software Foundation; either9* version 2.1 of the License, or (at your option) any later version.10*11* This library is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14* Lesser General Public License for more details.15*16* You should have received a copy of the GNU Lesser General Public17* License along with this library (in file ../LGPL-2.1); if not, write18* to the Free Software Foundation, Inc., 51 Franklin Street,19* Fifth Floor, Boston, MA 02110-1301 USA20*21*****************************************************************************/2223/*******************************************************************************24*25* The eigenvalue/eigenvector extraction routines.26*27*******************************************************************************28*29* Author: Juha Ruokolainen30*31* Address: CSC - IT Center for Science Ltd.32* Keilaranta 14, P.O. BOX 40533* 02101 Espoo, Finland34* Tel. +358 0 457 272335* Telefax: +358 0 457 230236* EMail: [email protected]37*38* Date: 30 May 199639*40* Modified by:41*42* Date of modification:43*44******************************************************************************/45/***********************************************************************46|47| EIG.C - Last Edited 8. 8. 198848|49***********************************************************************/5051/*======================================================================52|Syntax of the manual pages:53|54|FUNCTION NAME(...) params ...55|56$ usage of the function and type of the parameters57? explain the effects of the function58= return value and the type of value if not of type int59@ globals effected directly by this routine60! current known bugs or limitations61& functions called by this function62~ these functions may interest you as an alternative function or63| because they control this function somehow64^=====================================================================*/656667/*68* $Id: eig.c,v 1.1.1.1 2005/04/14 13:29:14 vierinen Exp $69*70* $Log: eig.c,v $71* Revision 1.1.1.1 2005/04/14 13:29:14 vierinen72* initial matc automake package73*74* Revision 1.2 1998/08/01 12:34:33 jpr75*76* Added Id, started Log.77*78*79*/8081#include "elmer/matc.h"8283#define A(i,j) a[n * (i) + (j)]8485#define MAXITER 100086#define EPS 1e-168788VARIABLE *mtr_hesse(VARIABLE *var)89{90VARIABLE *res;9192double *a;9394int n;9596if (NCOL(var) != NROW(var))97{98error( "hesse: matrix must be square, current dimensions: [%d,%d]\n", NROW(var), NCOL(var) );99}100101res = var_temp_copy(var);102103a = MATR(res); n = NROW(res);104if (NROW(res) == 1) return res;105106hesse(a, n, n);107108return res;109}110111VARIABLE *mtr_eig(VARIABLE *var)112{113VARIABLE *ptr, *res;114115int iter, i, j, k, n;116double *a, b, s, t;117118if (NCOL(var) != NROW(var))119{120error("eig: matrix must be square, current dimensions: [%d,%d]\n", NROW(var), NCOL(var));121}122123ptr = var_temp_copy(var);124125a = MATR(ptr); n = NROW(ptr);126127if (NROW(ptr) == 1) return ptr;128129hesse(a, n, n);130131for(iter = 0; iter < MAXITER; iter++)132{133134for (i = 0; i < n - 1; i++)135{136s = EPS*(abs(A(i,i))+abs(A(i+1,i+1)));137if (abs(A(i+1,i)) < s) A(i+1,i) = 0.0;138}139140i = 0;141do142{143for(j = i; j < n - 1; j++)144if (A(j+1,j) != 0) break;145146for(k = j; k < n - 1; k++)147if (A(k+1,k) == 0) break;148149i = k;150151} while(i < n - 1 && k - j + 1 < 3);152153if (k - j + 1 < 3) break;154155francis(&A(j,j), k - j + 1, n);156}157158res = var_temp_new(TYPE_DOUBLE, n, 2);159160for(i = 0, j = 0; i < n - 1; i++)161if (A(i+1,i) == 0)162M(res,j++,0) = A(i,i);163else164{165b = A(i,i) + A(i+1,i+1); s = b * b;166t = A(i,i) * A(i+1,i+1) - A(i,i+1)*A(i+1,i);167s = s - 4 * t;168if (s < 0)169{170M(res,j, 0) = b / 2;171M(res,j++, 1) = sqrt(-s) / 2;172M(res,j, 0) = b / 2;173M(res,j++,1) = -sqrt(-s) / 2;174}175else176{177M(res,j++, 0) = b / 2 + sqrt(s) / 2;178M(res,j++, 0) = b / 2 - sqrt(s) / 2;179}180i++;181}182183if (A(n-1, n-2) == 0) M(res,j,0) = A(n-1, n-1);184185var_delete_temp(ptr);186187return res;188}189190void vbcalc(double x[], double v[], double *b, int beg, int end)191{192double alpha,m,mp1;193int i;194195m = abs(x[beg]);196for(i = beg + 1; i <= end; i++)197m = max(m,abs(x[i]));198199if (m < EPS)200{201/*202* for(i = beg; i <= end; i++) v[i] = 0;203*/204memset(&v[beg], 0, (end-beg+1)<<3);205}206else207{208alpha = 0;209mp1 = 1 / m;210for(i = beg; i <= end; i++)211{212v[i] = x[i] * mp1;213alpha = alpha + v[i]*v[i];214}215alpha = sqrt(alpha);216*b = 1 / (alpha * (alpha + abs(v[beg])));217v[beg] = v[beg] + sign(v[beg]) * alpha;218}219return;220}221222#define H(i,j) h[(i) * N + (j)]223224void hesse(double *h, int DIM, int N)225{226double *v, *x, b, s;227int i, j, k;228229x = (double *)ALLOCMEM(DIM * sizeof(double));230v = (double *)ALLOCMEM(DIM * sizeof(double));231232for (i = 0; i < DIM - 2; i++)233{234235for(j = i + 1; j < DIM; j++) x[j] = H(j,i);236237vbcalc(x, v, &b, i + 1, DIM - 1);238239if (v[i+1] == 0) break;240241for(j = i + 2; j < DIM; j++)242{243x[j] = v[j]/v[i+1];244v[j] = b * v[i+1] * v[j];245}246v[i+1] = b * v[i+1] * v[i+1];247248for(j = 0; j < DIM; j++)249{250s = 0.0;251for(k = i + 1; k < DIM; k++)252s = s + H(j,k) * v[k];253H(j,i+1) = H(j,i+1) - s;254for(k = i + 2; k < DIM; k++)255H(j,k) = H(j,k) - s * x[k];256}257258for(j = 0; j < DIM; j++)259{260s = H(i+1,j);261for(k = i + 2; k < DIM; k++)262s = s + H(k,j) * x[k];263for(k = i + 1; k < DIM; k++)264H(k,j) = H(k,j) - s * v[k];265}266267for(j = i + 2; j < DIM; j++) H(j,i) = 0;268}269FREEMEM((char *)x); FREEMEM((char *)v);270271return;272}273274275void francis(double *h, int DIM, int N)276{277double x[3], v[3], b, s, t, bv, v0i;278int i, i1, j, k, n, m, end;279280n = DIM - 1; m = n - 1;281282t = H(m,m) * H(n,n) - H(m,n) * H(n,m);283s = H(m,m) + H(n,n);284285x[0] = H(0,0)*H(0,0)+H(0,1)*H(1,0)-s*H(0,0)+t;286x[1] = H(1,0) * (H(0,0) + H(1,1) - s);287x[2] = H(1,0) * H(2,1);288289vbcalc(x, v, &b, 0, 2);290291if (v[0] == 0) return;292293294295/*296* for(i = 1; i < 3; i++)297* {298* x[i] = v[i]/v[0];299* v[i] = b * v[0] * v[i];300* }301*/302bv = b * v[0];303304x[1] = v[1] / v[0];305v[1] = bv * v[1];306307x[2] = v[2] / v[0];308v[2] = bv * v[2];309310311312x[0] = 1; v[0] = b * v[0] * v[0];313314for(i = 0; i < DIM; i++)315{316/*317* s = 0.0;318* for(j = 0; j < 3; j++)319* s = s + H(i,j) * v[j];320*/321i1 = i * N;322s = h[i1] * v[0] + h[i1+1]*v[1] + h[i1+2]*v[2];323324325H(i,0) = H(i,0) - s;326/*327* for(j = 1; j < 3; j++)328* H(i,j) = H(i,j) - s * x[j];329*/330h[i1+1] = h[i1+1] - s * x[1];331h[i1+2] = h[i1+2] - s * x[2];332}333334for(i = 0; i < DIM; i++)335{336/*337* s = H(0,i);338* for(j = 1; j < 3; j++)339* s = s + H(j,i) * x[j];340*/341s = h[i] + h[N+i]*x[1] + h[(N<<1)+i]*x[2];342/*343* for(j = 0; j < 3; j++)344* H(j,i) = H(j,i) - s * v[j];345*/346h[i] = h[i] - s * v[0];347h[N+i] = h[N+i] - s * v[1];348h[(N<<1)+i] = h[(N<<1)+i] - s * v[2];349}350351for (i = 0; i < DIM - 2; i++)352{353354end = min(2, DIM - i - 2);355for(j = 0; j <= end; j++) x[j] = H(i+j+1,i);356357vbcalc(x, v, &b, 0, end);358359if (v[0] == 0) break;360361for(j = 1; j <= end; j++)362{363x[j] = v[j]/v[0];364v[j] = b * v[0] * v[j];365}366x[0] = 1; v[0] = b * v[0] * v[0];367368for(j = 0; j < DIM; j++)369{370s = 0.0;371for(k = 0; k <= end; k++)372s = s + H(j,i+k+1) * v[k];373H(j,i+1) = H(j,i+1) - s;374for(k = 1; k <= end; k++)375H(j,i+k+1) = H(j,i+k+1) - s * x[k];376}377378for(j = 0; j < DIM; j++)379{380s = H(i+1,j);381for(k = 1; k <= end; k++)382s = s + H(i+k+1,j) * x[k];383for(k = 0; k <= end; k++)384H(i+k+1,j) = H(i+k+1,j) - s * v[k];385}386387for(j = i + 2; j < DIM; j++) H(j,i) = 0;388}389return;390}391392393