Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 
22 ARPACKm3::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 
49 ARPACKm3::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 
76 ARPACKm3::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 
104 ARPACKm3::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 
132 int ARPACKm3::solve(int numEigen, Epetra_MultiVector &Q, double *lambda) {
133 
134  return ARPACKm3::reSolve(numEigen, Q, lambda, 0);
135 
136 }
137 
138 
139 int 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 
432 void 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 
450 void 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 
461 void 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 
489 void 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 
514 void 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 
MPI_Comm Comm() const