Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
22 ARPACKm1::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 
46 ARPACKm1::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 
70 int ARPACKm1::solve(int numEigen, Epetra_MultiVector &Q, double *lambda) {
71 
72  return ARPACKm1::reSolve(numEigen, Q, lambda, 0);
73 
74 }
75 
76 
77 int 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 
328 void 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 
344 void 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 
355 void 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 
383 void 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 
405 void 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 
MPI_Comm Comm() const