Anasazi Version of the Day
Loading...
Searching...
No Matches
ARPACKm3.cpp
1// @HEADER
2// *****************************************************************************
3// Anasazi: Block Eigensolvers Package
4//
5// Copyright 2004 NTESS and the Anasazi contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10// This software is a result of the research described in the report
11//
12// "A comparison of algorithms for modal analysis in the absence
13// of a sparse direct method", P. Arbenz, R. Lehoucq, and U. Hetmaniuk,
14// Sandia National Laboratories, Technical report SAND2003-1028J.
15//
16// It is based on the Epetra, AztecOO, and ML packages defined in the Trilinos
17// framework ( http://trilinos.org/ ).
18
19#include "ARPACKm3.h"
20
21
22ARPACKm3::ARPACKm3(const Epetra_Comm &_Comm, const Epetra_Operator *KK,
23 double _tol, int _maxIter, int _verb) :
24 myVerify(_Comm),
25 callFortran(),
26 MyComm(_Comm),
27 K(KK),
28 M(0),
29 MyWatch(_Comm),
30 tolEigenSolve(_tol),
31 maxIterEigenSolve(_maxIter),
32 which("LM"),
33 verbose(_verb),
34 memRequested(0.0),
35 highMem(0.0),
36 massOp(0),
37 orthoOp(0),
38 outerIter(0),
39 stifOp(0),
40 timeMassOp(0.0),
41 timeOuterLoop(0.0),
42 timePostProce(0.0),
43 timeStifOp(0.0)
44 {
45
46}
47
48
49ARPACKm3::ARPACKm3(const Epetra_Comm &_Comm, const Epetra_Operator *KK, char *_which,
50 double _tol, int _maxIter, int _verb) :
51 myVerify(_Comm),
52 callFortran(),
53 MyComm(_Comm),
54 K(KK),
55 M(0),
56 MyWatch(_Comm),
57 tolEigenSolve(_tol),
58 maxIterEigenSolve(_maxIter),
59 which(_which),
60 verbose(_verb),
61 memRequested(0.0),
62 highMem(0.0),
63 massOp(0),
64 orthoOp(0),
65 outerIter(0),
66 stifOp(0),
67 timeMassOp(0.0),
68 timeOuterLoop(0.0),
69 timePostProce(0.0),
70 timeStifOp(0.0)
71 {
72
73}
74
75
76ARPACKm3::ARPACKm3(const Epetra_Comm &_Comm, const Epetra_Operator *KK,
77 const Epetra_Operator *MM,
78 double _tol, int _maxIter, int _verb) :
79 myVerify(_Comm),
80 callFortran(),
81 MyComm(_Comm),
82 K(KK),
83 M(MM),
84 MyWatch(_Comm),
85 tolEigenSolve(_tol),
86 maxIterEigenSolve(_maxIter),
87 which("LM"),
88 verbose(_verb),
89 memRequested(0.0),
90 highMem(0.0),
91 massOp(0),
92 orthoOp(0),
93 outerIter(0),
94 stifOp(0),
95 timeMassOp(0.0),
96 timeOuterLoop(0.0),
97 timePostProce(0.0),
98 timeStifOp(0.0)
99 {
100
101}
102
103
104ARPACKm3::ARPACKm3(const Epetra_Comm &_Comm, const Epetra_Operator *KK,
105 const Epetra_Operator *MM, char *_which,
106 double _tol, int _maxIter, int _verb) :
107 myVerify(_Comm),
108 callFortran(),
109 MyComm(_Comm),
110 K(KK),
111 M(MM),
112 MyWatch(_Comm),
113 tolEigenSolve(_tol),
114 maxIterEigenSolve(_maxIter),
115 which(_which),
116 verbose(_verb),
117 memRequested(0.0),
118 highMem(0.0),
119 massOp(0),
120 orthoOp(0),
121 outerIter(0),
122 stifOp(0),
123 timeMassOp(0.0),
124 timeOuterLoop(0.0),
125 timePostProce(0.0),
126 timeStifOp(0.0)
127 {
128
129}
130
131
132int ARPACKm3::solve(int numEigen, Epetra_MultiVector &Q, double *lambda) {
133
134 return ARPACKm3::reSolve(numEigen, Q, lambda, 0);
135
136}
137
138
139int ARPACKm3::reSolve(int numEigen, Epetra_MultiVector &Q, double *lambda, int startingEV) {
140
141 // Computes eigenvalues and the corresponding eigenvectors
142 // of the generalized eigenvalue problem
143 //
144 // K X = M X Lambda
145 //
146 // using ARPACK (mode 3).
147 //
148 // The convergence test is provided by ARPACK.
149 //
150 // Note that if M is not specified, then K X = X Lambda is solved.
151 // (using the mode for generalized eigenvalue problem).
152 //
153 // Input variables:
154 //
155 // numEigen (integer) = Number of eigenmodes requested
156 //
157 // Q (Epetra_MultiVector) = Initial search space
158 // The number of columns of Q defines the size of search space (=NCV).
159 // The rows of X are distributed across processors.
160 // As a rule of thumb in ARPACK User's guide, NCV >= 2*numEigen.
161 // At exit, the first numEigen locations contain the eigenvectors requested.
162 //
163 // lambda (array of doubles) = Converged eigenvalues
164 // The length of this array is equal to the number of columns in Q.
165 // At exit, the first numEigen locations contain the eigenvalues requested.
166 //
167 // startingEV (integer) = Number of eigenmodes already stored in Q
168 // A linear combination of these vectors is made to define the starting
169 // vector, placed in resid.
170 //
171 // Return information on status of computation
172 //
173 // info >= 0 >> Number of converged eigenpairs at the end of computation
174 //
175 // // Failure due to input arguments
176 //
177 // info = - 1 >> The stiffness matrix K has not been specified.
178 // info = - 2 >> The maps for the matrix K and the matrix M differ.
179 // info = - 3 >> The maps for the matrix K and the preconditioner P differ.
180 // info = - 4 >> The maps for the vectors and the matrix K differ.
181 // info = - 5 >> Q is too small for the number of eigenvalues requested.
182 // info = - 6 >> Q is too small for the computation parameters.
183 //
184 // info = - 8 >> numEigen must be smaller than the dimension of the matrix.
185 //
186 // info = - 30 >> MEMORY
187 //
188 // See ARPACK documentation for the meaning of INFO
189
190 if (numEigen <= startingEV) {
191 return numEigen;
192 }
193
194 int info = myVerify.inputArguments(numEigen, K, M, 0, Q, minimumSpaceDimension(numEigen));
195 if (info < 0)
196 return info;
197
198 int myPid = MyComm.MyPID();
199
200 int localSize = Q.MyLength();
201 int NCV = Q.NumVectors();
202 int knownEV = 0;
203
204 if (NCV > Q.GlobalLength()) {
205 if (numEigen >= Q.GlobalLength()) {
206 cerr << endl;
207 cerr << " !! The number of requested eigenvalues must be smaller than the dimension";
208 cerr << " of the matrix !!\n";
209 cerr << endl;
210 return -8;
211 }
212 NCV = Q.GlobalLength();
213 }
214
215 int localVerbose = verbose*(myPid == 0);
216
217 // Define data for ARPACK
218 highMem = (highMem > currentSize()) ? highMem : currentSize();
219
220 int ido = 0;
221
222 int lwI = 22 + NCV;
223 int *wI = new (nothrow) int[lwI];
224 if (wI == 0) {
225 return -30;
226 }
227 memRequested += sizeof(int)*lwI/(1024.0*1024.0);
228
229 int *iparam = wI;
230 int *ipntr = wI + 11;
231 int *select = wI + 22;
232
233 int lworkl = NCV*(NCV+8);
234 int lwD = lworkl + 4*localSize;
235 double *wD = new (nothrow) double[lwD];
236 if (wD == 0) {
237 delete[] wI;
238 return -30;
239 }
240 memRequested += sizeof(double)*(4*localSize+lworkl)/(1024.0*1024.0);
241
242 double *pointer = wD;
243
244 double *workl = pointer;
245 pointer = pointer + lworkl;
246
247 double *resid = pointer;
248 pointer = pointer + localSize;
249
250 double *workd = pointer;
251
252 double *v = Q.Values();
253
254 highMem = (highMem > currentSize()) ? highMem : currentSize();
255
256 double sigma = 0.0;
257
258 if (startingEV > 0) {
259 // Define the initial starting vector
260 memset(resid, 0, localSize*sizeof(double));
261 for (int jj = 0; jj < startingEV; ++jj)
262 for (int ii = 0; ii < localSize; ++ii)
263 resid[ii] += v[ii + jj*localSize];
264 info = 1;
265 }
266
267 iparam[1-1] = 1;
268 iparam[3-1] = maxIterEigenSolve;
269 iparam[7-1] = 3;
270
271 // The fourth parameter forces to use the convergence test provided by ARPACK.
272 // This requires a customization of ARPACK (provided by R. Lehoucq).
273
274 iparam[4-1] = 0;
275
276 Epetra_Vector v1(View, Q.Map(), workd);
277 Epetra_Vector v2(View, Q.Map(), workd + localSize);
278 Epetra_Vector v3(View, Q.Map(), workd + 2*localSize);
279
280 double *vTmp = new (nothrow) double[localSize];
281 if (vTmp == 0) {
282 delete[] wI;
283 delete[] wD;
284 return -30;
285 }
286 memRequested += sizeof(double)*localSize/(1024.0*1024.0);
287
288 highMem = (highMem > currentSize()) ? highMem : currentSize();
289
290 if (localVerbose > 0) {
291 cout << endl;
292 cout << " *|* Problem: ";
293 if (M)
294 cout << "K*Q = M*Q D ";
295 else
296 cout << "K*Q = Q D ";
297 cout << endl;
298 cout << " *|* Algorithm = ARPACK (mode 3)" << endl;
299 cout << " *|* Number of requested eigenvalues = " << numEigen << endl;
300 cout.precision(2);
301 cout.setf(ios::scientific, ios::floatfield);
302 cout << " *|* Tolerance for convergence = " << tolEigenSolve << endl;
303 if (startingEV > 0)
304 cout << " *|* User-defined starting vector (Combination of " << startingEV << " vectors)\n";
305 cout << "\n -- Start iterations -- \n";
306 }
307
308#ifdef EPETRA_MPI
309 Epetra_MpiComm *MPIComm = dynamic_cast<Epetra_MpiComm *>(const_cast<Epetra_Comm*>(&MyComm));
310#endif
311
312 timeOuterLoop -= MyWatch.WallTime();
313 while (ido != 99) {
314
315 highMem = (highMem > currentSize()) ? highMem : currentSize();
316
317#ifdef EPETRA_MPI
318 if (MPIComm)
319 callFortran.PSAUPD(MPIComm->Comm(), &ido, 'G', localSize, which, numEigen, tolEigenSolve,
320 resid, NCV, v, localSize, iparam, ipntr, workd, workl, lworkl, &info, localVerbose);
321 else
322 callFortran.SAUPD(&ido, 'G', localSize, which, numEigen, tolEigenSolve, resid, NCV, v,
323 localSize, iparam, ipntr, workd, workl, lworkl, &info, localVerbose);
324#else
325 callFortran.SAUPD(&ido, 'G', localSize, which, numEigen, tolEigenSolve, resid, NCV, v,
326 localSize, iparam, ipntr, workd, workl, lworkl, &info, localVerbose);
327#endif
328
329 if (ido == -1) {
330 // Apply the mass matrix
331 v3.ResetView(workd + ipntr[0] - 1);
332 v1.ResetView(vTmp);
333 timeMassOp -= MyWatch.WallTime();
334 if (M)
335 M->Apply(v3, v1);
336 else
337 memcpy(v1.Values(), v3.Values(), localSize*sizeof(double));
338 timeMassOp += MyWatch.WallTime();
339 massOp += 1;
340 // Solve the stiffness problem
341 v2.ResetView(workd + ipntr[1] - 1);
342 timeStifOp -= MyWatch.WallTime();
343 K->ApplyInverse(v1, v2);
344 timeStifOp += MyWatch.WallTime();
345 stifOp += 1;
346 continue;
347 } // if (ido == -1)
348
349 if (ido == 1) {
350 // Solve the stiffness problem
351 v1.ResetView(workd + ipntr[2] - 1);
352 v2.ResetView(workd + ipntr[1] - 1);
353 timeStifOp -= MyWatch.WallTime();
354 K->ApplyInverse(v1, v2);
355 timeStifOp += MyWatch.WallTime();
356 stifOp += 1;
357 continue;
358 } // if (ido == 1)
359
360 if (ido == 2) {
361 // Apply the mass matrix
362 v1.ResetView(workd + ipntr[0] - 1);
363 v2.ResetView(workd + ipntr[1] - 1);
364 timeMassOp -= MyWatch.WallTime();
365 if (M)
366 M->Apply(v1, v2);
367 else
368 memcpy(v2.Values(), v1.Values(), localSize*sizeof(double));
369 timeMassOp += MyWatch.WallTime();
370 massOp += 1;
371 continue;
372 } // if (ido == 2)
373
374 } // while (ido != 99)
375 timeOuterLoop += MyWatch.WallTime();
376 highMem = (highMem > currentSize()) ? highMem : currentSize();
377
378 if (info < 0) {
379 if (myPid == 0) {
380 cerr << endl;
381 cerr << " Error with DSAUPD, info = " << info << endl;
382 cerr << endl;
383 }
384 }
385 else {
386
387 // Compute the eigenvectors
388 timePostProce -= MyWatch.WallTime();
389#ifdef EPETRA_MPI
390 if (MPIComm)
391 callFortran.PSEUPD(MPIComm->Comm(), 1, 'A', select, lambda, v, localSize, sigma, 'G',
392 localSize, which, numEigen, tolEigenSolve, resid, NCV, v, localSize, iparam, ipntr,
393 workd, workl, lworkl, &info);
394 else
395 callFortran.SEUPD(1, 'A', select, lambda, v, localSize, sigma, 'G', localSize, which,
396 numEigen, tolEigenSolve, resid, NCV, v, localSize, iparam, ipntr, workd, workl,
397 lworkl, &info);
398#else
399 callFortran.SEUPD(1, 'A', select, lambda, v, localSize, sigma, 'G', localSize, which,
400 numEigen, tolEigenSolve, resid, NCV, v, localSize, iparam, ipntr, workd, workl,
401 lworkl, &info);
402#endif
403 timePostProce += MyWatch.WallTime();
404 highMem = (highMem > currentSize()) ? highMem : currentSize();
405
406 // Treat the error
407 if (info != 0) {
408 if (myPid == 0) {
409 cerr << endl;
410 cerr << " Error with DSEUPD, info = " << info << endl;
411 cerr << endl;
412 }
413 }
414
415 } // if (info < 0)
416
417 if (info == 0) {
418 outerIter = iparam[3-1];
419 knownEV = iparam[5-1];
420 orthoOp = iparam[11-1];
421 }
422
423 delete[] wI;
424 delete[] wD;
425 delete[] vTmp;
426
427 return (info == 0) ? knownEV : info;
428
429}
430
431
432void ARPACKm3::initializeCounters() {
433
434 memRequested = 0.0;
435 highMem = 0.0;
436
437 massOp = 0;
438 orthoOp = 0;
439 outerIter = 0;
440 stifOp = 0;
441
442 timeMassOp = 0.0;
443 timeOuterLoop = 0.0;
444 timePostProce = 0.0;
445 timeStifOp = 0.0;
446
447}
448
449
450void ARPACKm3::algorithmInfo() const {
451
452 int myPid = MyComm.MyPID();
453
454 if (myPid ==0) {
455 cout << " Algorithm: ARPACK (Mode 3)\n";
456 }
457
458}
459
460
461void ARPACKm3::memoryInfo() const {
462
463 int myPid = MyComm.MyPID();
464
465 double maxHighMem = 0.0;
466 double tmp = highMem;
467 MyComm.MaxAll(&tmp, &maxHighMem, 1);
468
469 double maxMemRequested = 0.0;
470 tmp = memRequested;
471 MyComm.MaxAll(&tmp, &maxMemRequested, 1);
472
473 if (myPid == 0) {
474 cout.precision(2);
475 cout.setf(ios::fixed, ios::floatfield);
476 cout << " Memory requested per processor by the eigensolver = (EST) ";
477 cout.width(6);
478 cout << maxMemRequested << " MB " << endl;
479 cout << endl;
480 cout << " High water mark in eigensolver = (EST) ";
481 cout.width(6);
482 cout << maxHighMem << " MB " << endl;
483 cout << endl;
484 }
485
486}
487
488
489void ARPACKm3::operationInfo() const {
490
491 int myPid = MyComm.MyPID();
492
493 if (myPid == 0) {
494 cout << " --- Operations ---\n\n";
495 cout << " Total number of mass matrix multiplications = ";
496 cout.width(9);
497 cout << massOp << endl;
498 cout << " Total number of orthogonalizations = ";
499 cout.width(9);
500 cout << orthoOp << endl;
501 cout << " Total number of stiffness matrix operations = ";
502 cout.width(9);
503 cout << stifOp << endl;
504 cout << endl;
505 cout << " Total number of outer iterations = ";
506 cout.width(9);
507 cout << outerIter << endl;
508 cout << endl;
509 }
510
511}
512
513
514void ARPACKm3::timeInfo() const {
515
516 int myPid = MyComm.MyPID();
517
518 if (myPid == 0) {
519 cout << " --- Timings ---\n\n";
520 cout.setf(ios::fixed, ios::floatfield);
521 cout.precision(2);
522 cout << " Total time for outer loop = ";
523 cout.width(9);
524 cout << timeOuterLoop << " s" << endl;
525 cout << " Time for mass matrix operations = ";
526 cout.width(9);
527 cout << timeMassOp << " s ";
528 cout.width(5);
529 cout << 100*timeMassOp/timeOuterLoop << " %\n";
530 cout << " Time for stiffness matrix solves = ";
531 cout.width(9);
532 cout << timeStifOp << " s ";
533 cout.width(5);
534 cout << 100*timeStifOp/timeOuterLoop << " %\n";
535 cout << endl;
536 cout << " Total time for post-processing = ";
537 cout.width(9);
538 cout << timePostProce << " s\n";
539 cout << endl;
540 } // if (myId == 0)
541
542}
543
544