OOFEM 3.0
Loading...
Searching...
No Matches
gjacobi.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35
36#include "gjacobi.h"
37#include "mathfem.h"
38#include "floatmatrix.h"
39
40namespace oofem {
41GJacobi :: GJacobi(Domain *d, EngngModel *m) :
42 NumericalMethod(d, m)
43{
44 nsmax = 15; // default maximum number of sweeps allowed
45 rtol = 10.E-12; // convergence tolerance
46}
47
48GJacobi :: ~GJacobi() { }
49
50
51#define GJacobi_ZERO_CHECK_TOL 1.e-40
52
54GJacobi :: solve(FloatMatrix &a, FloatMatrix &b, FloatArray &eigv, FloatMatrix &x)
55//
56// this function solve the generalized eigenproblem using the Generalized
57// jacobi iteration
58//
59//
60{
61 int nsweep, nr;
62 double eps, eptola, eptolb, akk, ajj, ab, check, sqch, d1, d2, den, ca, cg, ak, bk, xj, xk;
63 double aj, bj;
64 int jm1, kp1, km1, jp1;
65
66 if ( a.giveNumberOfRows() != b.giveNumberOfRows() ||
67 !a.isSquare() || !b.isSquare() ) {
68 OOFEM_ERROR("A matrix, B mtrix -> size mismatch");
69 }
70
71 int n = a.giveNumberOfRows();
72 eigv.resize(n);
73 x.resize(n, n);
74
75 //
76 // Create temporary arrays
77 //
78 FloatArray d(n);
79 //
80 // Initialize EigenValue and EigenVector Matrices
81 //
82 for ( int i = 1; i <= n; i++ ) {
83 // if((a.at(i,i) <= 0. ) && (b.at(i,i) <= 0.))
84 // OOFEM_ERROR("Matrices are not positive definite");
85 d.at(i) = a.at(i, i) / b.at(i, i);
86 eigv.at(i) = d.at(i);
87 }
88
89 x.beUnitMatrix();
90
91 if ( n == 1 ) {
92 return CR_CONVERGED;
93 }
94
95 //
96 // Initialize sweep counter and begin iteration
97 //
98 nsweep = 0;
99 nr = n - 1;
100
101 do {
102 nsweep++;
103# ifdef DETAILED_REPORT
104 OOFEM_LOG_DEBUG("*GJacobi*: sweep number %4d\n", nsweep);
105#endif
106 //
107 // check if present off-diagonal element is large enough to require zeroing
108 //
109 eps = pow(0.01, ( double ) nsweep);
110 eps *= eps;
111 for ( int j = 1; j <= nr; j++ ) {
112 int jj = j + 1;
113 for ( int k = jj; k <= n; k++ ) {
114 eptola = ( a.at(j, k) * a.at(j, k) ) / ( a.at(j, j) * a.at(k, k) );
115 eptolb = ( b.at(j, k) * b.at(j, k) ) / ( b.at(j, j) * b.at(k, k) );
116 if ( ( eptola < eps ) && ( eptolb < eps ) ) {
117 continue;
118 }
119
120 //
121 // if zeroing is required, calculate the rotation matrix elements ca and cg
122 //
123 akk = a.at(k, k) * b.at(j, k) - b.at(k, k) * a.at(j, k);
124 ajj = a.at(j, j) * b.at(j, k) - b.at(j, j) * a.at(j, k);
125 ab = a.at(j, j) * b.at(k, k) - a.at(k, k) * b.at(j, j);
126 check = ( ab * ab + 4.0 * akk * ajj ) / 4.0;
127 if ( fabs(check) < GJacobi_ZERO_CHECK_TOL ) {
128 check = fabs(check);
129 } else if ( check < 0.0 ) {
130 OOFEM_ERROR("Matrices are not positive definite");
131 }
132
133 sqch = sqrt(check);
134 d1 = ab / 2. + sqch;
135 d2 = ab / 2. - sqch;
136 den = d1;
137 if ( fabs(d2) > fabs(d1) ) {
138 den = d2;
139 }
140
141 if ( den != 0.0 ) { // strange !
142 ca = akk / den;
143 cg = -ajj / den;
144 } else {
145 ca = 0.0;
146 cg = -a.at(j, k) / a.at(k, k);
147 }
148
149 //
150 // perform the generalized rotation to zero
151 //
152 if ( ( n - 2 ) != 0 ) {
153 jp1 = j + 1;
154 jm1 = j - 1;
155 kp1 = k + 1;
156 km1 = k - 1;
157 if ( ( jm1 - 1 ) >= 0 ) {
158 for ( int i = 1; i <= jm1; i++ ) {
159 aj = a.at(i, j);
160 bj = b.at(i, j);
161 ak = a.at(i, k);
162 bk = b.at(i, k);
163 a.at(i, j) = aj + cg * ak;
164 b.at(i, j) = bj + cg * bk;
165 a.at(i, k) = ak + ca * aj;
166 b.at(i, k) = bk + ca * bj;
167 }
168 }
169
170 if ( ( kp1 - n ) <= 0 ) {
171 for ( int i = kp1; i <= n; i++ ) { // label 140
172 aj = a.at(j, i);
173 bj = b.at(j, i);
174 ak = a.at(k, i);
175 bk = b.at(k, i);
176 a.at(j, i) = aj + cg * ak;
177 b.at(j, i) = bj + cg * bk;
178 a.at(k, i) = ak + ca * aj;
179 b.at(k, i) = bk + ca * bj;
180 }
181 }
182
183 if ( ( jp1 - km1 ) <= 0 ) { // label 160
184 for ( int i = jp1; i <= km1; i++ ) {
185 aj = a.at(j, i);
186 bj = b.at(j, i);
187 ak = a.at(i, k);
188 bk = b.at(i, k);
189 a.at(j, i) = aj + cg * ak;
190 b.at(j, i) = bj + cg * bk;
191 a.at(i, k) = ak + ca * aj;
192 b.at(i, k) = bk + ca * bj;
193 }
194 }
195 } // label 190
196
197 ak = a.at(k, k);
198 bk = b.at(k, k);
199 a.at(k, k) = ak + 2.0 *ca *a.at(j, k) + ca *ca *a.at(j, j);
200 b.at(k, k) = bk + 2.0 *ca *b.at(j, k) + ca *ca *b.at(j, j);
201 a.at(j, j) = a.at(j, j) + 2.0 *cg *a.at(j, k) + cg * cg * ak;
202 b.at(j, j) = b.at(j, j) + 2.0 *cg *b.at(j, k) + cg * cg * bk;
203 a.at(j, k) = 0.0;
204 b.at(j, k) = 0.0;
205 //
206 // update the eigenvector matrix after each rotation
207 //
208 for ( int i = 1; i <= n; i++ ) {
209 xj = x.at(i, j);
210 xk = x.at(i, k);
211 x.at(i, j) = xj + cg * xk;
212 x.at(i, k) = xk + ca * xj;
213 } // label 200
214 }
215 } // label 210
216
217 //
218 // update the eigenvalues after each sweep
219 //
220#ifdef DETAILED_REPORT
221 OOFEM_LOG_DEBUG("GJacobi: a,b after sweep\n");
222 a.printYourself();
223 b.printYourself();
224#endif
225 for ( int i = 1; i <= n; i++ ) {
226 // in original uncommented
227 // if ((a.at(i,i) <= 0.) || (b.at(i,i) <= 0.))
228 // error ("solveYourselfAt: Matrices are not positive definite");
229 eigv.at(i) = a.at(i, i) / b.at(i, i);
230 } // label 220
231
232# ifdef DETAILED_REPORT
233 OOFEM_LOG_DEBUG("GJacobi: current eigenvalues are:\n");
234 eigv.printYourself();
235 OOFEM_LOG_DEBUG("GJacobi: current eigenvectors are:\n");
236 x.printYourself();
237# endif
238 //
239 // check for convergence
240 //
241 for ( int i = 1; i <= n; i++ ) { // label 230
242 double tol = rtol * d.at(i);
243 double dif = ( eigv.at(i) - d.at(i) );
244 if ( fabs(dif) > tol ) {
245 goto label280;
246 }
247 } // label 240
248
249 //
250 // check all off-diagonal elements to see if another sweep is required
251 //
252 eps = rtol * rtol;
253 for ( int j = 1; j <= nr; j++ ) {
254 int jj = j + 1;
255 for ( int k = jj; k <= n; k++ ) {
256 double epsa = ( a.at(j, k) * a.at(j, k) ) / ( a.at(j, j) * a.at(k, k) );
257 double epsb = ( b.at(j, k) * b.at(j, k) ) / ( b.at(j, j) * b.at(k, k) );
258 if ( ( epsa < eps ) && ( epsb < eps ) ) {
259 continue;
260 }
261
262 goto label280;
263 }
264 } // label 250
265
266 //
267 // fill out bottom triangle of resultant matrices and scale eigenvectors
268 //
269 break;
270 // goto label255 ;
271 //
272 // update d matrix and start new sweep, if allowed
273 //
274label280:
275 d = eigv;
276 } while ( nsweep < nsmax );
277
278 // label255:
279 for ( int i = 1; i <= n; i++ ) {
280 for ( int j = 1; j <= n; j++ ) {
281 a.at(j, i) = a.at(i, j);
282 b.at(j, i) = b.at(i, j);
283 } // label 260
284 }
285
286 for ( int j = 1; j <= n; j++ ) {
287 double bb = sqrt( fabs( b.at(j, j) ) );
288 for ( int k = 1; k <= n; k++ ) {
289 x.at(k, j) /= bb;
290 }
291 } // label 270
292
293 if (nsweep<nsmax) {
294 return CR_CONVERGED;
295 } else {
296 return CR_DIVERGED_ITS;
297 }
298}
299} // end namespace oofem
void resize(Index s)
Definition floatarray.C:94
double & at(Index i)
Definition floatarray.h:202
virtual void printYourself() const
Definition floatarray.C:762
void resize(Index rows, Index cols)
Definition floatmatrix.C:79
*Prints matrix to stdout Useful for debugging void printYourself() const
int giveNumberOfRows() const
Returns number of rows of receiver.
double at(std::size_t i, std::size_t j) const
void beUnitMatrix()
Sets receiver to unity matrix.
bool isSquare() const
Returns nonzero if receiver is square matrix.
double rtol
Definition gjacobi.h:57
NumericalMethod(Domain *d, EngngModel *m)
Definition nummet.h:94
#define OOFEM_ERROR(...)
Definition error.h:79
#define GJacobi_ZERO_CHECK_TOL
Definition gjacobi.C:51
#define OOFEM_LOG_DEBUG(...)
Definition logger.h:144
@ CR_DIVERGED_ITS

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011