Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/matc/src/jacobi.c
3196 views
1
/*****************************************************************************
2
*
3
* Elmer, A Finite Element Software for Multiphysical Problems
4
*
5
* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
*
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library (in file ../LGPL-2.1); if not, write
19
* to the Free Software Foundation, Inc., 51 Franklin Street,
20
* Fifth Floor, Boston, MA 02110-1301 USA
21
*
22
*****************************************************************************/
23
24
/*******************************************************************************
25
*
26
* Solve symmetric positive definite eigenvalue problem.
27
*
28
*******************************************************************************
29
*
30
* Author: Juha Ruokolainen
31
*
32
* Address: CSC - IT Center for Science Ltd.
33
* Keilaranta 14, P.O. BOX 405
34
* 02101 Espoo, Finland
35
* Tel. +358 0 457 2723
36
* Telefax: +358 0 457 2302
37
* EMail: [email protected]
38
*
39
* Date: 30 May 1996
40
*
41
* Modified by:
42
*
43
* Date of modification:
44
*
45
******************************************************************************/
46
47
/*
48
* $Id: jacobi.c,v 1.1.1.1 2005/04/14 13:29:14 vierinen Exp $
49
*
50
* $Log: jacobi.c,v $
51
* Revision 1.1.1.1 2005/04/14 13:29:14 vierinen
52
* initial matc automake package
53
*
54
* Revision 1.2 1998/08/01 12:34:43 jpr
55
*
56
* Added Id, started Log.
57
*
58
*
59
*/
60
61
#include "elmer/matc.h"
62
63
/************************************************************************
64
P R O G R A M
65
To solve the generalized eigenproblem using the
66
generalized Jacobi iteration
67
68
INPUT
69
70
a(n,n) = Stiffness matrix (assumed positive definite)
71
b(n,n) = Mass matrix (assumed positive definite)
72
x(n,n) = Matrix storing eigenvectors on solution exit
73
eigv(n) = Vector storing eigenvalues on solution exit
74
d(n) = Working vector
75
n = Order of the matrices a and b
76
rtol = Convergence tolerance (usually set to 10.**-12)
77
nsmax = Maximum number of sweeps allowed (usually set to 15)
78
79
OUTPUT
80
81
a(n,n) = Diagonalized stiffness matrix
82
b(n,n) = Diagonalized mass matrix
83
x(n,n) = Eigenvectors stored columnwise
84
eigv(n) = Eigenvalues
85
86
*************************************************************************/
87
88
int matc_jacobi(double a[], double b[], double x[], double eigv[], double d[],
89
int n, double rtol)
90
{
91
register int i,j,k,ii,jj;
92
int nsmax=50, /* Max number of sweeps */
93
nsweep, /* Current sweep number */
94
nr,
95
jp1,jm1,kp1,km1,
96
convergence;
97
98
double eps,
99
eptola,eptolb,
100
akk,ajj,ab,
101
check,sqch,
102
d1,d2,den,
103
ca,cg,
104
aj,bj,ak,bk,
105
xj,xk,
106
tol,dif,
107
epsa,epsb,
108
bb; /* Scale mass matrix */
109
110
/************************************************************************
111
Initialize eigenvalue and eigenvector matrices
112
*************************************************************************/
113
for( i=0 ; i<n ; i++)
114
{
115
ii = i*n+i; /* address of diagonal element */
116
if (a[ii]<=0.0 || b[ii]<=0.0) return 0;
117
eigv[i] = d[i] = a[ii]/b[ii];
118
x[ii] = 1.0; /* make an unit matrix */
119
}
120
if(n==1) return 1; /* Return if single degree of freedom system */
121
122
/************************************************************************
123
Initialize sweep counter and begin iteration
124
*************************************************************************/
125
nr=n - 1;
126
for ( nsweep = 0; nsweep < nsmax; nsweep++)
127
{
128
/************************************************************************
129
Check if present off-diagonal element is large enough to require zeroing
130
*************************************************************************/
131
132
eps = pow(0.01, 2.0 * (nsweep + 1));
133
for(j=0 ; j<nr ; j++)
134
{
135
jj=j+1;
136
for(k=jj ; k<n ; k++)
137
{
138
eptola=( a[j*n+k]*a[j*n+k] / ( a[j*n+j]*a[k*n+k] ) );
139
eptolb=( b[j*n+k]*b[j*n+k] / ( b[j*n+j]*b[k*n+k] ) );
140
if ( eptola >= eps || eptolb >=eps )
141
{
142
143
/************************************************************************
144
if zeroing is required, calculate the rotation matrix elements
145
*************************************************************************/
146
147
akk=a[k*n+k]*b[j*n+k] - b[k*n+k]*a[j*n+k];
148
ajj=a[j*n+j]*b[j*n+k] - b[j*n+j]*a[j*n+k];
149
ab =a[j*n+j]*b[k*n+k] - a[k*n+k]*b[j*n+j];
150
check=(ab*ab+4.0*akk*ajj)/4.0;
151
152
if (check<=0.0)
153
{
154
printf("***Error solution stop in *jacobi*\n");
155
printf(" check = %20.14e\n", check);
156
return 1;
157
}
158
sqch= sqrt(check);
159
d1 = ab/2.0+sqch;
160
d2 = ab/2.0-sqch;
161
den = d1;
162
if ( abs(d2) > abs(d1) ) den=d2;
163
164
if (den == 0.0)
165
{
166
ca=0.0;
167
cg= -a[j*n+k] / a[k*n+k];
168
}
169
else
170
{
171
ca= akk/den;
172
cg= -ajj/den;
173
}
174
/************************************************************************
175
Perform the generalized rotation to zero the present off-diagonal element
176
*************************************************************************/
177
if (n != 2)
178
{
179
jp1=j+1;
180
jm1=j-1;
181
kp1=k+1;
182
km1=k-1;
183
/**************************************/
184
if ( jm1 >= 0)
185
for (i=0 ; i<=jm1 ; i++)
186
{
187
aj = a[i*n+j];
188
bj = b[i*n+j];
189
ak = a[i*n+k];
190
bk = b[i*n+k];
191
a[i*n+j] = aj+cg*ak;
192
b[i*n+j] = bj+cg*bk;
193
a[i*n+k] = ak+ca*aj;
194
b[i*n+k] = bk+ca*bj;
195
};
196
/**************************************/
197
if ((kp1-n+1) <= 0)
198
for (i=kp1 ; i<n ; i++)
199
{
200
aj = a[j*n+i];
201
bj = b[j*n+i];
202
ak = a[k*n+i];
203
bk = b[k*n+i];
204
a[j*n+i] = aj+cg*ak;
205
b[j*n+i] = bj+cg*bk;
206
a[k*n+i] = ak+ca*aj;
207
b[k*n+i] = bk+ca*bj;
208
};
209
/**************************************/
210
if ((jp1-km1) <= 0.0)
211
for (i=jp1 ; i<=km1 ; i++)
212
{
213
aj = a[j*n+i];
214
bj = b[j*n+i];
215
ak = a[i*n+k];
216
bk = b[i*n+k];
217
a[j*n+i] = aj+cg*ak;
218
b[j*n+i] = bj+cg*bk;
219
a[i*n+k] = ak+ca*aj;
220
b[i*n+k] = bk+ca*bj;
221
};
222
};
223
224
ak = a[k*n+k];
225
bk = b[k*n+k];
226
a[k*n+k] = ak+2.0*ca*a[j*n+k]+ca*ca*a[j*n+j];
227
b[k*n+k] = bk+2.0*ca*b[j*n+k]+ca*ca*b[j*n+j];
228
a[j*n+j] = a[j*n+j]+2.0*cg*a[j*n+k]+cg*cg*ak;
229
b[j*n+j] = b[j*n+j]+2.0*cg*b[j*n+k]+cg*cg*bk;
230
a[j*n+k] = 0.0;
231
b[j*n+k] = 0.0;
232
233
/************************************************************************
234
Update the eigenvector matrix after each rotation
235
*************************************************************************/
236
for (i=0 ; i<n ; i++)
237
{
238
xj = x[i*n+j];
239
xk = x[i*n+k];
240
x[i*n+j] = xj+cg*xk;
241
x[i*n+k] = xk+ca*xj;
242
};
243
};
244
};
245
};
246
/************************************************************************
247
Update the eigenvalues after each sweep
248
*************************************************************************/
249
for (i=0 ; i<n ; i++)
250
{
251
ii=i*n+i;
252
if (a[ii]<=0.0 || b[ii]<=0.0)
253
{
254
error( "*** Error solution stop in *jacobi*\n Matrix not positive definite.");
255
};
256
eigv[i] = a[ii] / b[ii];
257
};
258
259
/************************************************************************
260
check for convergence
261
*************************************************************************/
262
convergence = 1;
263
for(i=0 ; i<n ; i++)
264
{
265
tol = rtol*d[i];
266
dif = abs(eigv[i]-d[i]);
267
if (dif > tol) convergence = 0;
268
if (! convergence) break;
269
};
270
/************************************************************************
271
check if all off-diag elements are satisfactorily small
272
*************************************************************************/
273
if (convergence)
274
{
275
eps=rtol*rtol;
276
for (j=0 ; j<nr ; j++)
277
{
278
jj=j+1;
279
for (k=jj ; k<n ; k++)
280
{
281
epsa = ( a[j*n+k]*a[j*n+k] / ( a[j*n+j]*a[k*n+k] ) );
282
epsb = ( b[j*n+k]*b[j*n+k] / ( b[j*n+j]*b[k*n+k] ) );
283
if ( epsa >= eps || epsb >=eps ) convergence = 0;
284
if (! convergence) break;
285
};
286
if (! convergence) break;
287
};
288
};
289
if (! convergence)
290
{
291
for (i=0 ; i<n ; i++)
292
d[i] = eigv[i];
293
};
294
if (convergence) break;
295
};
296
/************************************************************************
297
Fill out bottom triangle of resultant matrices and scale eigenvectors
298
*************************************************************************/
299
for (i=0 ; i<n ; i++)
300
for (j=i ; j<n ; j++)
301
{
302
b[j*n+i] = b[i*n+j];
303
a[j*n+i] = a[i*n+j];
304
};
305
306
for (j=0 ; j<n ; j++)
307
{
308
bb = sqrt( b[j*n+j] );
309
for (k=0 ; k<n ; k++)
310
x[k*n+j] /= bb;
311
};
312
PrintOut( "jacobi: nsweeps %d\n", nsweep );
313
return 1 ;
314
}
315
316
VARIABLE *mtr_jacob(VARIABLE *a)
317
{
318
VARIABLE *x, *ev;
319
320
double *b, *d, rtol;
321
int i, n;
322
323
if (NROW(a) != NCOL(a))
324
error("Jacob: Matrix must be square.\n");
325
326
b = MATR(NEXT(a));
327
n = NROW(a);
328
329
if (NROW(NEXT(a)) != NCOL(NEXT(a)) || n != NROW(NEXT(a)))
330
error("Jacob: Matrix dimensions incompatible.\n");
331
332
rtol = *MATR(NEXT(NEXT(a)));
333
334
x = var_new("eigv", TYPE_DOUBLE, NROW(a), NCOL(a));
335
d = (double *)ALLOCMEM(n * sizeof(double));
336
ev = var_temp_new(TYPE_DOUBLE, 1, n);
337
338
(void)matc_jacobi(MATR(a), b, MATR(x), MATR(ev), d, n, rtol);
339
FREEMEM((char *)d);
340
341
return ev;
342
}
343
344