Anasazi Version of the Day
Loading...
Searching...
No Matches
ARPACKm1.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 "ARPACKm1.h"
20
21
22ARPACKm1::ARPACKm1(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 MyWatch(_Comm),
29 tolEigenSolve(_tol),
30 maxIterEigenSolve(_maxIter),
31 which("LM"),
32 verbose(_verb),
33 memRequested(0.0),
34 highMem(0.0),
35 orthoOp(0),
36 outerIter(0),
37 stifOp(0),
38 timeOuterLoop(0.0),
39 timePostProce(0.0),
40 timeStifOp(0.0)
41 {
42
43}
44
45
46ARPACKm1::ARPACKm1(const Epetra_Comm &_Comm, const Epetra_Operator *KK, char *_which,
47 double _tol, int _maxIter, int _verb) :
48 myVerify(_Comm),
49 callFortran(),
50 MyComm(_Comm),
51 K(KK),
52 MyWatch(_Comm),
53 tolEigenSolve(_tol),
54 maxIterEigenSolve(_maxIter),
55 which(_which),
56 verbose(_verb),
57 memRequested(0.0),
58 highMem(0.0),
59 orthoOp(0),
60 outerIter(0),
61 stifOp(0),
62 timeOuterLoop(0.0),
63 timePostProce(0.0),
64 timeStifOp(0.0)
65 {
66
67}
68
69
70int ARPACKm1::solve(int numEigen, Epetra_MultiVector &Q, double *lambda) {
71
72 return ARPACKm1::reSolve(numEigen, Q, lambda, 0);
73
74}
75
76
77int ARPACKm1::reSolve(int numEigen, Epetra_MultiVector &Q, double *lambda, int startingEV) {
78
79 // Computes eigenvalues and the corresponding eigenvectors
80 // of the generalized eigenvalue problem
81 //
82 // K X = X Lambda
83 //
84 // using ARPACK (mode 1).
85 //
86 // The convergence test is provided by ARPACK.
87 //
88 // Input variables:
89 //
90 // numEigen (integer) = Number of eigenmodes requested
91 //
92 // Q (Epetra_MultiVector) = Initial search space
93 // The number of columns of Q defines the size of search space (=NCV).
94 // The rows of X are distributed across processors.
95 // As a rule of thumb in ARPACK User's guide, NCV >= 2*numEigen.
96 // At exit, the first numEigen locations contain the eigenvectors requested.
97 //
98 // lambda (array of doubles) = Converged eigenvalues
99 // The length of this array is equal to the number of columns in Q.
100 // At exit, the first numEigen locations contain the eigenvalues requested.
101 //
102 // startingEV (integer) = Number of eigenmodes already stored in Q
103 // A linear combination of these vectors is made to define the starting
104 // vector, placed in resid.
105 //
106 // Return information on status of computation
107 //
108 // info >= 0 >> Number of converged eigenpairs at the end of computation
109 //
110 // // Failure due to input arguments
111 //
112 // info = - 1 >> The stiffness matrix K has not been specified.
113 // info = - 3 >> The maps for the matrix K and the preconditioner P differ.
114 // info = - 4 >> The maps for the vectors and the matrix K differ.
115 // info = - 5 >> Q is too small for the number of eigenvalues requested.
116 // info = - 6 >> Q is too small for the computation parameters.
117 //
118 // info = - 8 >> numEigen must be smaller than the dimension of the matrix.
119 //
120 // info = - 30 >> MEMORY
121 //
122 // See ARPACK documentation for the meaning of INFO
123
124 if (numEigen <= startingEV) {
125 return numEigen;
126 }
127
128 int info = myVerify.inputArguments(numEigen, K, 0, 0, Q, minimumSpaceDimension(numEigen));
129 if (info < 0)
130 return info;
131
132 int myPid = MyComm.MyPID();
133
134 int localSize = Q.MyLength();
135 int NCV = Q.NumVectors();
136 int knownEV = 0;
137
138 if (NCV > Q.GlobalLength()) {
139 if (numEigen >= Q.GlobalLength()) {
140 cerr << endl;
141 cerr << " !! The number of requested eigenvalues must be smaller than the dimension";
142 cerr << " of the matrix !!\n";
143 cerr << endl;
144 return -8;
145 }
146 NCV = Q.GlobalLength();
147 }
148
149 int localVerbose = verbose*(myPid == 0);
150
151 // Define data for ARPACK
152 highMem = (highMem > currentSize()) ? highMem : currentSize();
153
154 int ido = 0;
155
156 int lwI = 22 + NCV;
157 int *wI = new (nothrow) int[lwI];
158 if (wI == 0) {
159 return -30;
160 }
161 memRequested += sizeof(int)*lwI/(1024.0*1024.0);
162
163 int *iparam = wI;
164 int *ipntr = wI + 11;
165 int *select = wI + 22;
166
167 int lworkl = NCV*(NCV+8);
168 int lwD = lworkl + 4*localSize;
169 double *wD = new (nothrow) double[lwD];
170 if (wD == 0) {
171 delete[] wI;
172 return -30;
173 }
174 memRequested += sizeof(double)*(4*localSize+lworkl)/(1024.0*1024.0);
175
176 double *pointer = wD;
177
178 double *workl = pointer;
179 pointer = pointer + lworkl;
180
181 double *resid = pointer;
182 pointer = pointer + localSize;
183
184 double *workd = pointer;
185
186 double *v = Q.Values();
187
188 highMem = (highMem > currentSize()) ? highMem : currentSize();
189
190 double sigma = 0.0;
191
192 if (startingEV > 0) {
193 // Define the initial starting vector
194 memset(resid, 0, localSize*sizeof(double));
195 for (int jj = 0; jj < startingEV; ++jj)
196 for (int ii = 0; ii < localSize; ++ii)
197 resid[ii] += v[ii + jj*localSize];
198 info = 1;
199 }
200
201 iparam[1-1] = 1;
202 iparam[3-1] = maxIterEigenSolve;
203 iparam[7-1] = 1;
204
205 // The fourth parameter forces to use the convergence test provided by ARPACK.
206 // This requires a customization of ARPACK (provided by R. Lehoucq).
207 iparam[4-1] = 0;
208
209 Epetra_Vector v1(View, Q.Map(), workd);
210 Epetra_Vector v2(View, Q.Map(), workd + localSize);
211 Epetra_Vector v3(View, Q.Map(), workd + 2*localSize);
212
213 double *vTmp = new (nothrow) double[localSize];
214 if (vTmp == 0) {
215 delete[] wI;
216 delete[] wD;
217 return -30;
218 }
219 memRequested += sizeof(double)*localSize/(1024.0*1024.0);
220
221 highMem = (highMem > currentSize()) ? highMem : currentSize();
222
223 if (localVerbose > 0) {
224 cout << endl;
225 cout << " *|* Problem: ";
226 cout << "K*Q = Q D ";
227 cout << endl;
228 cout << " *|* Algorithm = ARPACK (mode 1)" << endl;
229 cout << " *|* Number of requested eigenvalues = " << numEigen << endl;
230 cout.precision(2);
231 cout.setf(ios::scientific, ios::floatfield);
232 cout << " *|* Tolerance for convergence = " << tolEigenSolve << endl;
233 if (startingEV > 0)
234 cout << " *|* User-defined starting vector (Combination of " << startingEV << " vectors)\n";
235 cout << "\n -- Start iterations -- \n";
236 }
237
238#ifdef EPETRA_MPI
239 Epetra_MpiComm *MPIComm = dynamic_cast<Epetra_MpiComm *>(const_cast<Epetra_Comm*>(&MyComm));
240#endif
241
242 timeOuterLoop -= MyWatch.WallTime();
243 while (ido != 99) {
244
245 highMem = (highMem > currentSize()) ? highMem : currentSize();
246
247#ifdef EPETRA_MPI
248 if (MPIComm)
249 callFortran.PSAUPD(MPIComm->Comm(), &ido, 'I', localSize, which, numEigen, tolEigenSolve,
250 resid, NCV, v, localSize, iparam, ipntr, workd, workl, lworkl, &info, localVerbose);
251 else
252 callFortran.SAUPD(&ido, 'I', localSize, which, numEigen, tolEigenSolve, resid, NCV, v,
253 localSize, iparam, ipntr, workd, workl, lworkl, &info, localVerbose);
254#else
255 callFortran.SAUPD(&ido, 'I', localSize, which, numEigen, tolEigenSolve, resid, NCV, v,
256 localSize, iparam, ipntr, workd, workl, lworkl, &info, localVerbose);
257#endif
258
259 if ((ido == 1) || (ido == -1)) {
260 // Apply the matrix
261 v1.ResetView(workd + ipntr[0] - 1);
262 v2.ResetView(workd + ipntr[1] - 1);
263 timeStifOp -= MyWatch.WallTime();
264 K->Apply(v1, v2);
265 timeStifOp += MyWatch.WallTime();
266 stifOp += 1;
267 continue;
268 } // if ((ido == 1) || (ido == -1))
269
270 } // while (ido != 99)
271 timeOuterLoop += MyWatch.WallTime();
272 highMem = (highMem > currentSize()) ? highMem : currentSize();
273
274 if (info < 0) {
275 if (myPid == 0) {
276 cerr << endl;
277 cerr << " Error with DSAUPD, info = " << info << endl;
278 cerr << endl;
279 }
280 }
281 else {
282
283 // Compute the eigenvectors
284 timePostProce -= MyWatch.WallTime();
285#ifdef EPETRA_MPI
286 if (MPIComm)
287 callFortran.PSEUPD(MPIComm->Comm(), 1, 'A', select, lambda, v, localSize, sigma, 'I',
288 localSize, which, numEigen, tolEigenSolve, resid, NCV, v, localSize, iparam, ipntr,
289 workd, workl, lworkl, &info);
290 else
291 callFortran.SEUPD(1, 'A', select, lambda, v, localSize, sigma, 'I', localSize, which,
292 numEigen, tolEigenSolve, resid, NCV, v, localSize, iparam, ipntr, workd, workl,
293 lworkl, &info);
294#else
295 callFortran.SEUPD(1, 'A', select, lambda, v, localSize, sigma, 'I', localSize, which,
296 numEigen, tolEigenSolve, resid, NCV, v, localSize, iparam, ipntr, workd, workl,
297 lworkl, &info);
298#endif
299 timePostProce += MyWatch.WallTime();
300 highMem = (highMem > currentSize()) ? highMem : currentSize();
301
302 // Treat the error
303 if (info != 0) {
304 if (myPid == 0) {
305 cerr << endl;
306 cerr << " Error with DSEUPD, info = " << info << endl;
307 cerr << endl;
308 }
309 }
310
311 } // if (info < 0)
312
313 if (info == 0) {
314 outerIter = iparam[3-1];
315 knownEV = iparam[5-1];
316 orthoOp = iparam[11-1];
317 }
318
319 delete[] wI;
320 delete[] wD;
321 delete[] vTmp;
322
323 return (info == 0) ? knownEV : info;
324
325}
326
327
328void ARPACKm1::initializeCounters() {
329
330 memRequested = 0.0;
331 highMem = 0.0;
332
333 orthoOp = 0;
334 outerIter = 0;
335 stifOp = 0;
336
337 timeOuterLoop = 0.0;
338 timePostProce = 0.0;
339 timeStifOp = 0.0;
340
341}
342
343
344void ARPACKm1::algorithmInfo() const {
345
346 int myPid = MyComm.MyPID();
347
348 if (myPid ==0) {
349 cout << " Algorithm: ARPACK (Mode 1)\n";
350 }
351
352}
353
354
355void ARPACKm1::memoryInfo() const {
356
357 int myPid = MyComm.MyPID();
358
359 double maxHighMem = 0.0;
360 double tmp = highMem;
361 MyComm.MaxAll(&tmp, &maxHighMem, 1);
362
363 double maxMemRequested = 0.0;
364 tmp = memRequested;
365 MyComm.MaxAll(&tmp, &maxMemRequested, 1);
366
367 if (myPid == 0) {
368 cout.precision(2);
369 cout.setf(ios::fixed, ios::floatfield);
370 cout << " Memory requested per processor by the eigensolver = (EST) ";
371 cout.width(6);
372 cout << maxMemRequested << " MB " << endl;
373 cout << endl;
374 cout << " High water mark in eigensolver = (EST) ";
375 cout.width(6);
376 cout << maxHighMem << " MB " << endl;
377 cout << endl;
378 }
379
380}
381
382
383void ARPACKm1::operationInfo() const {
384
385 int myPid = MyComm.MyPID();
386
387 if (myPid == 0) {
388 cout << " --- Operations ---\n\n";
389 cout << " Total number of orthogonalizations = ";
390 cout.width(9);
391 cout << orthoOp << endl;
392 cout << " Total number of stiffness matrix operations = ";
393 cout.width(9);
394 cout << stifOp << endl;
395 cout << endl;
396 cout << " Total number of outer iterations = ";
397 cout.width(9);
398 cout << outerIter << endl;
399 cout << endl;
400 }
401
402}
403
404
405void ARPACKm1::timeInfo() const {
406
407 int myPid = MyComm.MyPID();
408
409 if (myPid == 0) {
410 cout << " --- Timings ---\n\n";
411 cout.setf(ios::fixed, ios::floatfield);
412 cout.precision(2);
413 cout << " Total time for outer loop = ";
414 cout.width(9);
415 cout << timeOuterLoop << " s" << endl;
416 cout << " Time for stiffness matrix = ";
417 cout.width(9);
418 cout << timeStifOp << " s ";
419 cout.width(5);
420 cout << 100*timeStifOp/timeOuterLoop << " %\n";
421 cout << endl;
422 cout << " Total time for post-processing = ";
423 cout.width(9);
424 cout << timePostProce << " s\n";
425 cout << endl;
426 } // if (myId == 0)
427
428}
429
430