Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ModifiedARPACKm3.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 "ModifiedARPACKm3.h"
20 
21 
22 ModifiedARPACKm3::ModifiedARPACKm3(const Epetra_Comm &_Comm, const Epetra_Operator *KK,
23  double _tol, int _maxIter, int _verb) :
24  myVerify(_Comm),
25  callBLAS(),
26  callFortran(),
27  modalTool(_Comm),
28  mySort(),
29  MyComm(_Comm),
30  K(KK),
31  M(0),
32  MyWatch(_Comm),
33  tolEigenSolve(_tol),
34  maxIterEigenSolve(_maxIter),
35  normWeight(0),
36  verbose(_verb),
37  historyCount(0),
38  resHistory(0),
39  memRequested(0.0),
40  highMem(0.0),
41  massOp(0),
42  numResidual(0),
43  orthoOp(0),
44  outerIter(0),
45  stifOp(0),
46  timeMassOp(0.0),
47  timeOuterLoop(0.0),
48  timePostProce(0.0),
49  timeResidual(0.0),
50  timeStifOp(0.0)
51  {
52 
53 }
54 
55 
56 ModifiedARPACKm3::ModifiedARPACKm3(const Epetra_Comm &_Comm, const Epetra_Operator *KK,
57  const Epetra_Operator *MM,
58  double _tol, int _maxIter, int _verb, double *_weight) :
59  myVerify(_Comm),
60  callBLAS(),
61  callFortran(),
62  modalTool(_Comm),
63  mySort(),
64  MyComm(_Comm),
65  K(KK),
66  M(MM),
67  MyWatch(_Comm),
68  tolEigenSolve(_tol),
69  maxIterEigenSolve(_maxIter),
70  normWeight(_weight),
71  verbose(_verb),
72  historyCount(0),
73  resHistory(0),
74  memRequested(0.0),
75  highMem(0.0),
76  massOp(0),
77  numResidual(0),
78  orthoOp(0),
79  outerIter(0),
80  stifOp(0),
81  timeMassOp(0.0),
82  timeOuterLoop(0.0),
83  timePostProce(0.0),
84  timeResidual(0.0),
85  timeStifOp(0.0)
86  {
87 
88 }
89 
90 
91 ModifiedARPACKm3::~ModifiedARPACKm3() {
92 
93  if (resHistory) {
94  delete[] resHistory;
95  resHistory = 0;
96  }
97 
98 }
99 
100 
101 int ModifiedARPACKm3::solve(int numEigen, Epetra_MultiVector &Q, double *lambda) {
102 
103  return ModifiedARPACKm3::reSolve(numEigen, Q, lambda, 0, 0);
104 
105 }
106 
107 
108 int ModifiedARPACKm3::reSolve(int numEigen, Epetra_MultiVector &Q, double *lambda,
109  int startingEV) {
110 
111  return ModifiedARPACKm3::reSolve(numEigen, Q, lambda, startingEV, 0);
112 
113 }
114 
115 
116 int ModifiedARPACKm3::reSolve(int numEigen, Epetra_MultiVector &Q, double *lambda,
117  int startingEV, const Epetra_MultiVector *orthoVec) {
118 
119  // Computes the smallest eigenvalues and the corresponding eigenvectors
120  // of the generalized eigenvalue problem
121  //
122  // K X = M X Lambda
123  //
124  // using ModifiedARPACK (mode 3).
125  //
126  // The convergence test is performed outisde of ARPACK
127  //
128  // || Kx - Mx lambda || < tol*lambda
129  //
130  // The norm ||.|| can be specified by the user through the array normWeight.
131  // By default, the L2 Euclidean norm is used.
132  //
133  // Note that if M is not specified, then K X = X Lambda is solved.
134  // (using the mode for generalized eigenvalue problem).
135  //
136  // Input variables:
137  //
138  // numEigen (integer) = Number of eigenmodes requested
139  //
140  // Q (Epetra_MultiVector) = Initial search space
141  // The number of columns of Q defines the size of search space (=NCV).
142  // The rows of X are distributed across processors.
143  // As a rule of thumb in ARPACK User's guide, NCV >= 2*numEigen.
144  // At exit, the first numEigen locations contain the eigenvectors requested.
145  //
146  // lambda (array of doubles) = Converged eigenvalues
147  // The length of this array is equal to the number of columns in Q.
148  // At exit, the first numEigen locations contain the eigenvalues requested.
149  //
150  // startingEV (integer) = Number of eigenmodes already stored in Q
151  // A linear combination of these vectors is made to define the starting
152  // vector, placed in resid.
153  //
154  // orthoVec (Pointer to Epetra_MultiVector) = Space to be orthogonal to
155  // The computation is performed in the orthogonal of the space spanned
156  // by the columns vectors in orthoVec.
157  //
158  // Return information on status of computation
159  //
160  // info >= 0 >> Number of converged eigenpairs at the end of computation
161  //
162  // // Failure due to input arguments
163  //
164  // info = - 1 >> The stiffness matrix K has not been specified.
165  // info = - 2 >> The maps for the matrix K and the matrix M differ.
166  // info = - 3 >> The maps for the matrix K and the preconditioner P differ.
167  // info = - 4 >> The maps for the vectors and the matrix K differ.
168  // info = - 5 >> Q is too small for the number of eigenvalues requested.
169  // info = - 6 >> Q is too small for the computation parameters.
170  //
171  // info = - 8 >> numEigen must be smaller than the dimension of the matrix.
172  //
173  // info = - 30 >> MEMORY
174  //
175  // See ARPACK documentation for the meaning of INFO
176 
177  if (numEigen <= startingEV) {
178  return numEigen;
179  }
180 
181  int info = myVerify.inputArguments(numEigen, K, M, 0, Q, minimumSpaceDimension(numEigen));
182  if (info < 0)
183  return info;
184 
185  int myPid = MyComm.MyPID();
186 
187  int localSize = Q.MyLength();
188  int NCV = Q.NumVectors();
189  int knownEV = 0;
190 
191  if (NCV > Q.GlobalLength()) {
192  if (numEigen >= Q.GlobalLength()) {
193  cerr << endl;
194  cerr << " !! The number of requested eigenvalues must be smaller than the dimension";
195  cerr << " of the matrix !!\n";
196  cerr << endl;
197  return -8;
198  }
199  NCV = Q.GlobalLength();
200  }
201 
202  // Get the weight for approximating the M-inverse norm
203  Epetra_Vector *vectWeight = 0;
204  if (normWeight) {
205  vectWeight = new Epetra_Vector(View, Q.Map(), normWeight);
206  }
207 
208  int localVerbose = verbose*(myPid == 0);
209 
210  // Define data for ARPACK
211  //
212  // UH (10/17/03) Note that workl is also used
213  // * to store the eigenvectors of the tridiagonal matrix
214  // * as a workspace for DSTEQR
215  // * as a workspace for recovering the global eigenvectors
216 
217  highMem = (highMem > currentSize()) ? highMem : currentSize();
218 
219  int ido = 0;
220 
221  int lwI = 22;
222  int *wI = new (nothrow) int[lwI];
223  if (wI == 0) {
224  if (vectWeight)
225  delete vectWeight;
226  return -30;
227  }
228  memRequested += sizeof(int)*lwI/(1024.0*1024.0);
229 
230  int *iparam = wI;
231  int *ipntr = wI + 11;
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  if (vectWeight)
238  delete vectWeight;
239  delete[] wI;
240  return -30;
241  }
242  memRequested += sizeof(double)*(4*localSize+lworkl)/(1024.0*1024.0);
243 
244  double *pointer = wD;
245 
246  double *workl = pointer;
247  pointer = pointer + lworkl;
248 
249  double *resid = pointer;
250  pointer = pointer + localSize;
251 
252  double *workd = pointer;
253 
254  double *v = Q.Values();
255 
256  highMem = (highMem > currentSize()) ? highMem : currentSize();
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] = 1;
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  // Define further storage for the new residual check
281  // Use a block of vectors to compute the residuals more quickly.
282  // Note that workd could be used if memory becomes an issue.
283  int loopZ = (NCV > 10) ? 10 : NCV;
284 
285  int lwD2 = localSize + 2*NCV-1 + NCV;
286  lwD2 += (M) ? 3*loopZ*localSize : 2*loopZ*localSize;
287  double *wD2 = new (nothrow) double[lwD2];
288  if (wD2 == 0) {
289  if (vectWeight)
290  delete vectWeight;
291  delete[] wI;
292  delete[] wD;
293  return -30;
294  }
295  memRequested += sizeof(double)*lwD2/(1024.0*1024.0);
296 
297  pointer = wD2;
298 
299  // vTmp is used when ido = -1
300  double *vTmp = pointer;
301  pointer = pointer + localSize;
302 
303  // dd and ee stores the tridiagonal matrix.
304  // Note that DSTEQR destroys the contents of the input arrays.
305  double *dd = pointer;
306  pointer = pointer + NCV;
307 
308  double *ee = pointer;
309  pointer = pointer + NCV-1;
310 
311  double *vz = pointer;
312  pointer = pointer + loopZ*localSize;
313  Epetra_MultiVector approxEV(View, Q.Map(), vz, localSize, loopZ);
314 
315  double *kvz = pointer;
316  pointer = pointer + loopZ*localSize;
317  Epetra_MultiVector KapproxEV(View, Q.Map(), kvz, localSize, loopZ);
318 
319  double *mvz = (M) ? pointer : vz;
320  pointer = (M) ? pointer + loopZ*localSize : pointer;
321  Epetra_MultiVector MapproxEV(View, Q.Map(), mvz, localSize, loopZ);
322 
323  double *normR = pointer;
324 
325  // zz contains the eigenvectors of the tridiagonal matrix.
326  // workt is a workspace for DSTEQR.
327  // Note that zz and workt will use parts of workl.
328  double *zz, *workt;
329 
330  highMem = (highMem > currentSize()) ? highMem : currentSize();
331 
332  // Define an array to store the residuals history
333  if (localVerbose > 2) {
334  resHistory = new (nothrow) double[maxIterEigenSolve*NCV];
335  if (resHistory == 0) {
336  if (vectWeight)
337  delete vectWeight;
338  delete[] wI;
339  delete[] wD;
340  delete[] wD2;
341  return -30;
342  }
343  historyCount = 0;
344  }
345 
346  highMem = (highMem > currentSize()) ? highMem : currentSize();
347 
348  if (localVerbose > 0) {
349  cout << endl;
350  cout << " *|* Problem: ";
351  if (M)
352  cout << "K*Q = M*Q D ";
353  else
354  cout << "K*Q = Q D ";
355  cout << endl;
356  cout << " *|* Algorithm = ARPACK (Mode 3, modified such that user checks convergence)" << endl;
357  cout << " *|* Number of requested eigenvalues = " << numEigen << endl;
358  cout.precision(2);
359  cout.setf(ios::scientific, ios::floatfield);
360  cout << " *|* Tolerance for convergence = " << tolEigenSolve << endl;
361  if (startingEV > 0)
362  cout << " *|* User-defined starting vector (Combination of " << startingEV << " vectors)\n";
363  cout << " *|* Norm used for convergence: ";
364  if (normWeight)
365  cout << "weighted L2-norm with user-provided weights" << endl;
366  else
367  cout << "L^2-norm" << endl;
368  if (orthoVec)
369  cout << " *|* Size of orthogonal subspace = " << orthoVec->NumVectors() << endl;
370  cout << "\n -- Start iterations -- \n";
371  }
372 
373 #ifdef EPETRA_MPI
374  Epetra_MpiComm *MPIComm = dynamic_cast<Epetra_MpiComm *>(const_cast<Epetra_Comm*>(&MyComm));
375 #endif
376 
377  timeOuterLoop -= MyWatch.WallTime();
378  while (ido != 99) {
379 
380  highMem = (highMem > currentSize()) ? highMem : currentSize();
381 
382 #ifdef EPETRA_MPI
383  if (MPIComm)
384  callFortran.PSAUPD(MPIComm->Comm(), &ido, 'G', localSize, "LM", numEigen, tolEigenSolve,
385  resid, NCV, v, localSize, iparam, ipntr, workd, workl, lworkl, &info, 0);
386  else
387  callFortran.SAUPD(&ido, 'G', localSize, "LM", numEigen, tolEigenSolve, resid, NCV, v,
388  localSize, iparam, ipntr, workd, workl, lworkl, &info, 0);
389 #else
390  callFortran.SAUPD(&ido, 'G', localSize, "LM", numEigen, tolEigenSolve, resid, NCV, v,
391  localSize, iparam, ipntr, workd, workl, lworkl, &info, 0);
392 #endif
393 
394  if (ido == -1) {
395  // Apply the mass matrix
396  v3.ResetView(workd + ipntr[0] - 1);
397  v1.ResetView(vTmp);
398  timeMassOp -= MyWatch.WallTime();
399  if (M)
400  M->Apply(v3, v1);
401  else
402  memcpy(v1.Values(), v3.Values(), localSize*sizeof(double));
403  timeMassOp += MyWatch.WallTime();
404  massOp += 1;
405  if ((orthoVec) && (verbose > 3)) {
406  // Check the orthogonality
407  double maxDot = myVerify.errorOrthogonality(orthoVec, &v1, 0);
408  if (myPid == 0) {
409  cout << " Maximum Euclidean dot product against orthogonal space (Before Solve) = ";
410  cout << maxDot << endl;
411  }
412  }
413  // Solve the stiffness problem
414  v2.ResetView(workd + ipntr[1] - 1);
415  timeStifOp -= MyWatch.WallTime();
416  K->ApplyInverse(v1, v2);
417  timeStifOp += MyWatch.WallTime();
418  stifOp += 1;
419  // Project the solution vector if needed
420  // Note: Use mvz as workspace
421  if (orthoVec) {
422  Epetra_Vector Mv2(View, v2.Map(), mvz);
423  if (M)
424  M->Apply(v2, Mv2);
425  else
426  memcpy(Mv2.Values(), v2.Values(), localSize*sizeof(double));
427  modalTool.massOrthonormalize(v2, Mv2, M, *orthoVec, 1, 1);
428  }
429  if ((orthoVec) && (verbose > 3)) {
430  // Check the orthogonality
431  double maxDot = myVerify.errorOrthogonality(orthoVec, &v2, M);
432  if (myPid == 0) {
433  cout << " Maximum M-dot product against orthogonal space (After Solve) = ";
434  cout << maxDot << endl;
435  }
436  }
437  continue;
438  } // if (ido == -1)
439 
440  if (ido == 1) {
441  // Solve the stiffness problem
442  v1.ResetView(workd + ipntr[2] - 1);
443  v2.ResetView(workd + ipntr[1] - 1);
444  if ((orthoVec) && (verbose > 3)) {
445  // Check the orthogonality
446  double maxDot = myVerify.errorOrthogonality(orthoVec, &v1, 0);
447  if (myPid == 0) {
448  cout << " Maximum Euclidean dot product against orthogonal space (Before Solve) = ";
449  cout << maxDot << endl;
450  }
451  }
452  timeStifOp -= MyWatch.WallTime();
453  K->ApplyInverse(v1, v2);
454  timeStifOp += MyWatch.WallTime();
455  stifOp += 1;
456  // Project the solution vector if needed
457  // Note: Use mvz as workspace
458  if (orthoVec) {
459  Epetra_Vector Mv2(View, v2.Map(), mvz);
460  if (M)
461  M->Apply(v2, Mv2);
462  else
463  memcpy(Mv2.Values(), v2.Values(), localSize*sizeof(double));
464  modalTool.massOrthonormalize(v2, Mv2, M, *orthoVec, 1, 1);
465  }
466  if ((orthoVec) && (verbose > 3)) {
467  // Check the orthogonality
468  double maxDot = myVerify.errorOrthogonality(orthoVec, &v2, M);
469  if (myPid == 0) {
470  cout << " Maximum M-dot product against orthogonal space (After Solve) = ";
471  cout << maxDot << endl;
472  }
473  }
474  continue;
475  } // if (ido == 1)
476 
477  if (ido == 2) {
478  // Apply the mass matrix
479  v1.ResetView(workd + ipntr[0] - 1);
480  v2.ResetView(workd + ipntr[1] - 1);
481  timeMassOp -= MyWatch.WallTime();
482  if (M)
483  M->Apply(v1, v2);
484  else
485  memcpy(v2.Values(), v1.Values(), localSize*sizeof(double));
486  timeMassOp += MyWatch.WallTime();
487  massOp += 1;
488  continue;
489  } // if (ido == 2)
490 
491  if (ido == 4) {
492  timeResidual -= MyWatch.WallTime();
493  // Copy the main diagonal of T
494  memcpy(dd, workl + NCV + ipntr[4] - 1, NCV*sizeof(double));
495  // Copy the lower diagonal of T
496  memcpy(ee, workl + ipntr[4], (NCV-1)*sizeof(double));
497  // Compute the eigenpairs of the tridiagonal matrix
498  zz = workl + 4*NCV;
499  workt = workl + 4*NCV + NCV*NCV;
500  callFortran.STEQR('I', NCV, dd, ee, zz, NCV, workt, &info);
501  if (info != 0) {
502  if (localVerbose > 0) {
503  cerr << endl;
504  cerr << " Error with DSTEQR, info = " << info << endl;
505  cerr << endl;
506  }
507  break;
508  }
509  // dd contains the eigenvalues in ascending order
510  // Check the residual of the proposed eigenvectors of (K, M)
511  int ii, jz;
512  iparam[4] = 0;
513  for (jz = 0; jz < NCV; jz += loopZ) {
514  int colZ = (jz + loopZ < NCV) ? loopZ : NCV - jz;
515  callBLAS.GEMM('N', 'N', localSize, colZ, NCV, 1.0, v, localSize,
516  zz + jz*NCV, NCV, 0.0, vz, localSize);
517  // Form the residuals
518  if (M)
519  M->Apply(approxEV, MapproxEV);
520  K->Apply(approxEV, KapproxEV);
521  for (ii = 0; ii < colZ; ++ii) {
522  callBLAS.AXPY(localSize, -1.0/dd[ii+jz], MapproxEV.Values() + ii*localSize,
523  KapproxEV.Values() + ii*localSize);
524  }
525  // Compute the norms of the residuals
526  if (vectWeight) {
527  KapproxEV.NormWeighted(*vectWeight, normR + jz);
528  }
529  else {
530  KapproxEV.Norm2(normR + jz);
531  }
532  // Scale the norms of residuals with the eigenvalues
533  for (ii = 0; ii < colZ; ++ii) {
534  normR[ii+jz] = normR[ii+jz]*dd[ii+jz];
535  }
536  // Put the number of converged pairs in iparam[5-1]
537  for (ii=0; ii<colZ; ++ii) {
538  if (normR[ii+jz] < tolEigenSolve)
539  iparam[4] += 1;
540  }
541  }
542  timeResidual += MyWatch.WallTime();
543  numResidual += NCV;
544  outerIter += 1;
545  if (localVerbose > 0) {
546  cout << " Iteration " << outerIter;
547  cout << " - Number of converged eigenvalues " << iparam[4] << endl;
548  }
549  if (localVerbose > 2) {
550  memcpy(resHistory + historyCount, normR, NCV*sizeof(double));
551  historyCount += NCV;
552  }
553  if (localVerbose > 1) {
554  cout.precision(2);
555  cout.setf(ios::scientific, ios::floatfield);
556  for (ii=0; ii < NCV; ++ii) {
557  cout << " Iteration " << outerIter;
558  cout << " - Scaled Norm of Residual " << ii << " = " << normR[ii] << endl;
559  }
560  cout << endl;
561  cout.precision(2);
562  for (ii = 0; ii < NCV; ++ii) {
563  cout << " Iteration " << outerIter << " - Ritz eigenvalue " << ii;
564  cout.setf((fabs(dd[ii]) > 100) ? ios::scientific : ios::fixed, ios::floatfield);
565  cout << " = " << 1.0/dd[ii] << endl;
566  }
567  cout << endl;
568  }
569  } // if (ido == 4)
570 
571  } // while (ido != 99)
572  timeOuterLoop += MyWatch.WallTime();
573  highMem = (highMem > currentSize()) ? highMem : currentSize();
574 
575  if (info < 0) {
576  if (myPid == 0) {
577  cerr << endl;
578  cerr << " Error with DSAUPD, info = " << info << endl;
579  cerr << endl;
580  }
581  }
582  else {
583  // Get the eigenvalues
584  timePostProce -= MyWatch.WallTime();
585  int ii, jj;
586  double *pointer = workl + 4*NCV + NCV*NCV;
587  for (ii=0; ii < localSize; ii += 3) {
588  int nRow = (ii + 3 < localSize) ? 3 : localSize - ii;
589  for (jj=0; jj<NCV; ++jj)
590  memcpy(pointer + jj*nRow, v + ii + jj*localSize, nRow*sizeof(double));
591  callBLAS.GEMM('N', 'N', nRow, NCV, NCV, 1.0, pointer, nRow, zz, NCV,
592  0.0, Q.Values() + ii, localSize);
593  }
594  // Put the converged eigenpairs at the beginning
595  knownEV = 0;
596  for (ii=0; ii < NCV; ++ii) {
597  if (normR[ii] < tolEigenSolve) {
598  lambda[knownEV] = 1.0/dd[ii];
599  memcpy(Q.Values()+knownEV*localSize, Q.Values()+ii*localSize, localSize*sizeof(double));
600  knownEV += 1;
601  if (knownEV == Q.NumVectors())
602  break;
603  }
604  }
605  // Sort the eigenpairs
606  if (knownEV > 0) {
607  mySort.sortScalars_Vectors(knownEV, lambda, Q.Values(), localSize);
608  }
609  timePostProce += MyWatch.WallTime();
610  } // if (info < 0)
611 
612  if (info == 0) {
613  orthoOp = iparam[11-1];
614  }
615 
616  delete[] wI;
617  delete[] wD;
618  delete[] wD2;
619  if (vectWeight)
620  delete vectWeight;
621 
622  return (info == 0) ? knownEV : info;
623 
624 }
625 
626 
627 void ModifiedARPACKm3::initializeCounters() {
628 
629  historyCount = 0;
630  if (resHistory) {
631  delete[] resHistory;
632  resHistory = 0;
633  }
634 
635  memRequested = 0.0;
636  highMem = 0.0;
637 
638  massOp = 0;
639  numResidual = 0;
640  orthoOp = 0;
641  outerIter = 0;
642  stifOp = 0;
643 
644  timeMassOp = 0.0;
645  timeOuterLoop = 0.0;
646  timePostProce = 0.0;
647  timeResidual = 0.0;
648  timeStifOp = 0.0;
649 
650 }
651 
652 
653 void ModifiedARPACKm3::algorithmInfo() const {
654 
655  int myPid = MyComm.MyPID();
656 
657  if (myPid ==0) {
658  cout << " Algorithm: ARPACK (Mode 3, modified such that user checks convergence)\n";
659  }
660 
661 }
662 
663 
664 void ModifiedARPACKm3::memoryInfo() const {
665 
666  int myPid = MyComm.MyPID();
667 
668  double maxHighMem = 0.0;
669  double tmp = highMem;
670  MyComm.MaxAll(&tmp, &maxHighMem, 1);
671 
672  double maxMemRequested = 0.0;
673  tmp = memRequested;
674  MyComm.MaxAll(&tmp, &maxMemRequested, 1);
675 
676  if (myPid == 0) {
677  cout.precision(2);
678  cout.setf(ios::fixed, ios::floatfield);
679  cout << " Memory requested per processor by the eigensolver = (EST) ";
680  cout.width(6);
681  cout << maxMemRequested << " MB " << endl;
682  cout << endl;
683  cout << " High water mark in eigensolver = (EST) ";
684  cout.width(6);
685  cout << maxHighMem << " MB " << endl;
686  cout << endl;
687  }
688 
689 }
690 
691 
692 void ModifiedARPACKm3::historyInfo() const {
693 
694  if (resHistory) {
695  int j;
696  cout << " Residuals\n";
697  cout << endl;
698  cout.precision(4);
699  cout.setf(ios::scientific, ios::floatfield);
700  for (j = 0; j < historyCount; ++j) {
701  cout << resHistory[j] << endl;
702  }
703  cout << endl;
704  }
705 
706 }
707 
708 
709 void ModifiedARPACKm3::operationInfo() const {
710 
711  int myPid = MyComm.MyPID();
712 
713  if (myPid == 0) {
714  cout << " --- Operations ---\n\n";
715  cout << " Total number of mass matrix multiplications = ";
716  cout.width(9);
717  cout << massOp << endl;
718  cout << " Total number of orthogonalizations = ";
719  cout.width(9);
720  cout << orthoOp << endl;
721  cout << " Total number of stiffness matrix operations = ";
722  cout.width(9);
723  cout << stifOp << endl;
724  cout << " Total number of computed eigen-residuals = ";
725  cout.width(9);
726  cout << numResidual << endl;
727  cout << endl;
728  cout << " Total number of outer iterations = ";
729  cout.width(9);
730  cout << outerIter << endl;
731  cout << endl;
732  }
733 
734 }
735 
736 
737 void ModifiedARPACKm3::timeInfo() const {
738 
739  int myPid = MyComm.MyPID();
740 
741  if (myPid == 0) {
742  cout << " --- Timings ---\n\n";
743  cout.setf(ios::fixed, ios::floatfield);
744  cout.precision(2);
745  cout << " Total time for outer loop = ";
746  cout.width(9);
747  cout << timeOuterLoop << " s" << endl;
748  cout << " Time for mass matrix operations = ";
749  cout.width(9);
750  cout << timeMassOp << " s ";
751  cout.width(5);
752  cout << 100*timeMassOp/timeOuterLoop << " %\n";
753  cout << " Time for stiffness matrix solves = ";
754  cout.width(9);
755  cout << timeStifOp << " s ";
756  cout.width(5);
757  cout << 100*timeStifOp/timeOuterLoop << " %\n";
758  cout << " Time for residual computations = ";
759  cout.width(9);
760  cout << timeResidual << " s ";
761  cout.width(5);
762  cout << 100*timeResidual/timeOuterLoop << " %\n";
763  cout << endl;
764  cout << " Total time for post-processing = ";
765  cout.width(9);
766  cout << timePostProce << " s\n";
767  cout << endl;
768  } // if (myId == 0)
769 
770 }
771 
772 
MPI_Comm Comm() const