Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
CheckingTools.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 "CheckingTools.h"
20 
21 
22 CheckingTools::CheckingTools(const Epetra_Comm &_Comm) :
23  MyComm(_Comm) {
24 
25 }
26 
27 
28 double CheckingTools::errorOrthogonality(const Epetra_MultiVector *X,
29  const Epetra_MultiVector *R, const Epetra_Operator *M) const {
30 
31  // Return the maximum value of R_i^T * M * X_j / || MR_i || || X_j ||
32  // When M is not specified, the identity is used.
33  double maxDot = 0.0;
34 
35  int xc = (X) ? X->NumVectors() : 0;
36  int rc = (R) ? R->NumVectors() : 0;
37 
38  if (xc*rc == 0)
39  return maxDot;
40 
41  int i, j;
42  for (i = 0; i < rc; ++i) {
43  Epetra_Vector MRi(Copy, (*R), i);
44  if (M)
45  M->Apply(*((*R)(i)), MRi);
46  double normMR = 0.0;
47  MRi.Norm2(&normMR);
48  double dot = 0.0;
49  for (j = 0; j < xc; ++j) {
50  double normXj = 0.0;
51  (*X)(j)->Norm2(&normXj);
52  (*X)(j)->Dot(MRi, &dot);
53  dot = fabs(dot)/(normMR*normXj);
54  maxDot = (dot > maxDot) ? dot : maxDot;
55  }
56  }
57 
58  return maxDot;
59 
60 }
61 
62 
63 double CheckingTools::errorOrthonormality(const Epetra_MultiVector *X,
64  const Epetra_Operator *M) const {
65 
66  // Return the maximum coefficient of the matrix X^T * M * X - I
67  // When M is not specified, the identity is used.
68  double maxDot = 0.0;
69 
70  int xc = (X) ? X->NumVectors() : 0;
71  if (xc == 0)
72  return maxDot;
73 
74  int i, j;
75  for (i = 0; i < xc; ++i) {
76  Epetra_Vector MXi(Copy, (*X), i);
77  if (M)
78  M->Apply(*((*X)(i)), MXi);
79  double dot = 0.0;
80  for (j = 0; j < xc; ++j) {
81  (*X)(j)->Dot(MXi, &dot);
82  dot = (i == j) ? fabs(dot - 1.0) : fabs(dot);
83  maxDot = (dot > maxDot) ? dot : maxDot;
84  }
85  }
86 
87  return maxDot;
88 
89 }
90 
91 
92 double CheckingTools::errorEquality(const Epetra_MultiVector *X,
93  const Epetra_MultiVector *MX, const Epetra_Operator *M) const {
94 
95  // Return the maximum coefficient of the matrix M * X - MX
96  // scaled by the maximum coefficient of MX.
97  // When M is not specified, the identity is used.
98 
99  double maxDiff = 0.0;
100 
101  int xc = (X) ? X->NumVectors() : 0;
102  int mxc = (MX) ? MX->NumVectors() : 0;
103 
104  if ((xc != mxc) || (xc*mxc == 0))
105  return maxDiff;
106 
107  int i;
108  double maxCoeffX = 0.0;
109  for (i = 0; i < xc; ++i) {
110  double tmp = 0.0;
111  (*MX)(i)->NormInf(&tmp);
112  maxCoeffX = (tmp > maxCoeffX) ? tmp : maxCoeffX;
113  }
114 
115  for (i = 0; i < xc; ++i) {
116  Epetra_Vector MtimesXi(Copy, (*X), i);
117  if (M)
118  M->Apply(*((*X)(i)), MtimesXi);
119  MtimesXi.Update(-1.0, *((*MX)(i)), 1.0);
120  double diff = 0.0;
121  MtimesXi.NormInf(&diff);
122  maxDiff = (diff > maxDiff) ? diff : maxDiff;
123  }
124 
125  return (maxCoeffX == 0.0) ? maxDiff : maxDiff/maxCoeffX;
126 
127 }
128 
129 
130 int CheckingTools::errorSubspaces(const Epetra_MultiVector &Q, const Epetra_MultiVector &Qex,
131  const Epetra_Operator *M) const {
132 
133  int info = 0;
134  int myPid = MyComm.MyPID();
135 
136  int qr = Q.MyLength();
137  int qc = Q.NumVectors();
138  int qexc = Qex.NumVectors();
139 
140  double *mQ = new (nothrow) double[qr];
141  if (mQ == 0) {
142  info = -1;
143  return info;
144  }
145 
146  double *z = new (nothrow) double[qexc*qc];
147  if (z == 0) {
148  delete[] mQ;
149  info = -1;
150  return info;
151  }
152 
153  Epetra_LocalMap lMap(qexc, 0, MyComm);
154  Epetra_MultiVector QextMQ(View, lMap, z, qexc, qc);
155 
156  int j;
157  for (j=0; j<qc; ++j) {
158  Epetra_MultiVector Qj(View, Q, j, 1);
159  Epetra_MultiVector MQ(View, Q.Map(), mQ, qr, 1);
160  if (M)
161  M->Apply(Qj, MQ);
162  else
163  memcpy(mQ, Qj.Values(), qr*sizeof(double));
164  Epetra_MultiVector colJ(View, QextMQ, j, 1);
165  colJ.Multiply('T', 'N', 1.0, Qex, MQ, 0.0);
166  }
167  delete[] mQ;
168 
169  // Compute the SVD
170 
171  int svSize = (qc > qexc) ? qexc : qc;
172  double *sv = new (nothrow) double[svSize];
173  if (sv == 0) {
174  delete[] z;
175  info = -1;
176  return info;
177  }
178 
179  // lwork is larger than the value suggested by LAPACK
180  int lwork = (qexc > qc) ? qexc + 5*qc : qc + 5*qexc;
181  double *work = new (nothrow) double[lwork];
182  if (work == 0) {
183  delete[] z;
184  delete[] sv;
185  info = -1;
186  return info;
187  }
188 
189  Epetra_LAPACK call;
190  call.GESVD('N','N',qexc,qc,QextMQ.Values(),qexc,sv,0,qc,0,qc,work,&lwork,&info);
191 
192  delete[] work;
193  delete[] z;
194 
195  // Treat error messages
196 
197  if (info < 0) {
198  if (myPid == 0) {
199  cerr << endl;
200  cerr << " In DGESVD, argument " << -info << " has an illegal value\n";
201  cerr << endl;
202  }
203  delete[] sv;
204  return info;
205  }
206 
207  if (info > 0) {
208  if (myPid == 0) {
209  cerr << endl;
210  cerr << " In DGESVD, DBSQR did not converge (" << info << ").\n";
211  cerr << endl;
212  }
213  delete[] sv;
214  return info;
215  }
216 
217  // Output the result
218 
219  if (myPid == 0) {
220  cout << endl;
221  cout << " --- Principal angles between eigenspaces ---\n";
222  cout << endl;
223  cout << " Reference space built with " << Qex.NumVectors() << " vectors." << endl;
224  cout << " Dimension of computed space: " << Q.NumVectors() << endl;
225  cout << endl;
226  cout.setf(ios::scientific, ios::floatfield);
227  cout.precision(4);
228  cout << " Smallest singular value = " << sv[0] << endl;
229  cout << " Largest singular value = " << sv[svSize-1] << endl;
230  cout << endl;
231  cout << " Smallest angle between subspaces (rad) = ";
232  cout << ((sv[0] > 1.0) ? 0.0 : asin(sqrt(1.0 - sv[0]*sv[0]))) << endl;
233  cout << " Largest angle between subspaces (rad) = ";
234  cout << ((sv[0] > 1.0) ? 0.0 : asin(sqrt(1.0 - sv[svSize-1]*sv[svSize-1]))) << endl;
235  cout << endl;
236  }
237 
238  delete[] sv;
239 
240  return info;
241 
242 }
243 
244 
245 void CheckingTools::errorEigenResiduals(const Epetra_MultiVector &Q, double *lambda,
246  const Epetra_Operator *K, const Epetra_Operator *M,
247  double *normWeight) const {
248 
249  if ((K == 0) || (lambda == 0))
250  return;
251 
252  int myPid = MyComm.MyPID();
253 
254  int qr = Q.MyLength();
255  int qc = Q.NumVectors();
256 
257  double *work = new (nothrow) double[2*qr];
258  if (work == 0)
259  return;
260 
261  if (myPid == 0) {
262  cout << endl;
263  cout << " --- Norms of residuals for computed eigenmodes ---\n";
264  cout << endl;
265  cout << " Eigenvalue";
266  if (normWeight)
267  cout << " User Norm Scaled User N.";
268  cout << " 2-Norm Scaled 2-Nor.\n";
269  }
270 
271  Epetra_Vector KQ(View, Q.Map(), work);
272  Epetra_Vector MQ(View, Q.Map(), work + qr);
273  Epetra_Vector Qj(View, Q.Map(), Q.Values());
274 
275  double maxUserNorm = 0.0;
276  double minUserNorm = 1.0e+100;
277  double maxL2Norm = 0.0;
278  double minL2Norm = 1.0e+100;
279 
280  // Compute the residuals and norms
281  int j;
282  for (j=0; j<qc; ++j) {
283 
284  Qj.ResetView(Q.Values() + j*qr);
285  if (M)
286  M->Apply(Qj, MQ);
287  else
288  memcpy(MQ.Values(), Qj.Values(), qr*sizeof(double));
289  K->Apply(Qj, KQ);
290  KQ.Update(-lambda[j], MQ, 1.0);
291 
292  double residualL2 = 0.0;
293  KQ.Norm2(&residualL2);
294 
295  double residualUser = 0.0;
296  if (normWeight) {
297  Epetra_Vector vectWeight(View, Q.Map(), normWeight);
298  KQ.NormWeighted(vectWeight, &residualUser);
299  }
300 
301  if (myPid == 0) {
302  cout << " ";
303  cout.width(4);
304  cout.precision(8);
305  cout.setf(ios::scientific, ios::floatfield);
306  cout << j+1 << ". " << lambda[j] << " ";
307  if (normWeight) {
308  cout << residualUser << " ";
309  cout << ((lambda[j] == 0.0) ? 0.0 : residualUser/lambda[j]) << " ";
310  }
311  cout << residualL2 << " " << ((lambda[j] == 0.0) ? 0.0 : residualL2/lambda[j]) << " ";
312  cout << endl;
313  }
314 
315  if (lambda[j] > 0.0) {
316  maxL2Norm = (residualL2/lambda[j] > maxL2Norm) ? residualL2/lambda[j] : maxL2Norm;
317  minL2Norm = (residualL2/lambda[j] < minL2Norm) ? residualL2/lambda[j] : minL2Norm;
318  if (normWeight) {
319  maxUserNorm = (residualUser/lambda[j] > maxUserNorm) ? residualUser/lambda[j]
320  : maxUserNorm;
321  minUserNorm = (residualUser/lambda[j] < minUserNorm) ? residualUser/lambda[j]
322  : minUserNorm;
323  }
324  }
325 
326  } // for j=0; j<qc; ++j)
327 
328  if (myPid == 0) {
329  cout << endl;
330  if (normWeight) {
331  cout << " >> Minimum scaled user-norm of residuals = " << minUserNorm << endl;
332  cout << " >> Maximum scaled user-norm of residuals = " << maxUserNorm << endl;
333  cout << endl;
334  }
335  cout << " >> Minimum scaled L2 norm of residuals = " << minL2Norm << endl;
336  cout << " >> Maximum scaled L2 norm of residuals = " << maxL2Norm << endl;
337  cout << endl;
338  }
339 
340  if (work)
341  delete[] work;
342 
343 }
344 
345 
346 void CheckingTools::errorEigenResiduals(const Epetra_MultiVector &Q, double *lambda,
347  const Epetra_Operator *K, const Epetra_Operator *M,
348  const Epetra_Operator *Msolver) const {
349 
350  if ((K == 0) || (lambda == 0) || (Msolver == 0))
351  return;
352 
353  int myPid = MyComm.MyPID();
354 
355  int qr = Q.MyLength();
356  int qc = Q.NumVectors();
357 
358  double *work = new (nothrow) double[2*qr];
359  if (work == 0)
360  return;
361 
362  if (myPid == 0) {
363  cout << endl;
364  cout << " --- Norms of residuals for computed eigenmodes ---\n";
365  cout << endl;
366  cout << " Eigenvalue";
367  cout << " M^{-1} N. Sca. M^{-1} N.";
368  cout << " 2-Norm Scaled 2-Nor.\n";
369  }
370 
371  Epetra_Vector KQ(View, Q.Map(), work);
372  Epetra_Vector MQ(View, Q.Map(), work + qr);
373  Epetra_Vector Qj(View, Q.Map(), Q.Values());
374 
375  double maxMinvNorm = 0.0;
376  double minMinvNorm = 1.0e+100;
377  double maxL2Norm = 0.0;
378  double minL2Norm = 1.0e+100;
379 
380  // Compute the residuals and norms
381  int j;
382  for (j=0; j<qc; ++j) {
383 
384  Qj.ResetView(Q.Values() + j*qr);
385  if (M)
386  M->Apply(Qj, MQ);
387  else
388  memcpy(MQ.Values(), Qj.Values(), qr*sizeof(double));
389  K->Apply(Qj, KQ);
390  KQ.Update(-lambda[j], MQ, 1.0);
391 
392  double residualL2 = 0.0;
393  KQ.Norm2(&residualL2);
394 
395  double residualMinv = 0.0;
396  Msolver->ApplyInverse(KQ, MQ);
397  KQ.Dot(MQ, &residualMinv);
398  residualMinv = sqrt(fabs(residualMinv));
399 
400  if (myPid == 0) {
401  cout << " ";
402  cout.width(4);
403  cout.precision(8);
404  cout.setf(ios::scientific, ios::floatfield);
405  cout << j+1 << ". " << lambda[j] << " ";
406  cout << residualMinv << " ";
407  cout << ((lambda[j] == 0.0) ? 0.0 : residualMinv/lambda[j]) << " ";
408  cout << residualL2 << " " << ((lambda[j] == 0.0) ? 0.0 : residualL2/lambda[j]) << " ";
409  cout << endl;
410  }
411 
412  if (lambda[j] > 0.0) {
413  maxL2Norm = (residualL2/lambda[j] > maxL2Norm) ? residualL2/lambda[j] : maxL2Norm;
414  minL2Norm = (residualL2/lambda[j] < minL2Norm) ? residualL2/lambda[j] : minL2Norm;
415  maxMinvNorm = (residualMinv/lambda[j] > maxMinvNorm) ? residualMinv/lambda[j]
416  : maxMinvNorm;
417  minMinvNorm = (residualMinv/lambda[j] < minMinvNorm) ? residualMinv/lambda[j]
418  : minMinvNorm;
419  }
420 
421  } // for j=0; j<qc; ++j)
422 
423  if (myPid == 0) {
424  cout << endl;
425  cout << " >> Minimum scaled M^{-1}-norm of residuals = " << minMinvNorm << endl;
426  cout << " >> Maximum scaled M^{-1}-norm of residuals = " << maxMinvNorm << endl;
427  cout << endl;
428  cout << " >> Minimum scaled L2 norm of residuals = " << minL2Norm << endl;
429  cout << " >> Maximum scaled L2 norm of residuals = " << maxL2Norm << endl;
430  cout << endl;
431  }
432 
433  if (work)
434  delete[] work;
435 
436 }
437 
438 
439 int CheckingTools::errorLambda(double *continuous, double *discrete, int numDiscrete,
440  double *lambda, int nev) const {
441 
442  int myPid = MyComm.MyPID();
443  int nMax = 0;
444  int i, j;
445 
446  // Allocate working arrays
447 
448  int *used = new (nothrow) int[numDiscrete + nev];
449  if (used == 0) {
450  return nMax;
451  }
452 
453  int *bestMatch = used + numDiscrete;
454 
455  // Find the best match for the eigenvalues
456  double eps = 0.0;
457  Epetra_LAPACK call;
458  call.LAMCH('E', eps);
459 
460  double gap = Epetra_MaxDouble;
461  for (i=0; i<numDiscrete; ++i) {
462  used[i] = -1;
463  for (j = i; j < numDiscrete; ++j) {
464  if (discrete[j] > (1.0 + 10.0*eps)*discrete[i]) {
465  double tmp = (discrete[j] - discrete[i])/discrete[i];
466  gap = (tmp < gap) ? tmp : gap;
467  break;
468  }
469  }
470  }
471 
472  for (i=0; i<nev; ++i) {
473  bestMatch[i] = -1;
474  }
475 
476  for (i=0; i<nev; ++i) {
477  if (lambda[i] < continuous[0]) {
478  continue;
479  }
480  bestMatch[i] = (i == 0) ? 0 : bestMatch[i-1] + 1;
481  int jStart = bestMatch[i];
482  for (j = jStart; j < numDiscrete; ++j) {
483  double diff = fabs(lambda[i]-discrete[j]);
484  if (diff < 0.5*gap*lambda[i]) {
485  bestMatch[i] = j;
486  break;
487  }
488  }
489  used[bestMatch[i]] = i;
490  }
491 
492  // Print the results for the eigenvalues
493  if (myPid == 0) {
494  cout << endl;
495  cout << " --- Relative errors on eigenvalues ---\n";
496  cout << endl;
497  cout << " Exact Cont. Exact Disc. Computed ";
498  cout << " Alg. Err. Mesh Err.\n";
499  }
500 
501  int iCount = 0;
502  for (i=0; i<nev; ++i) {
503  if (bestMatch[i] == -1) {
504  if (myPid == 0) {
505  cout << " ************** ************** ";
506  cout.precision(8);
507  cout.setf(ios::scientific, ios::floatfield);
508  cout << lambda[i];
509  cout << " ********* *********" << endl;
510  }
511  iCount += 1;
512  }
513  }
514 
515  double lastDiscrete = 0.0;
516  for (i=0; i<numDiscrete; ++i) {
517  if ((iCount == nev) && (discrete[i] > lastDiscrete)) {
518  break;
519  }
520  if (used[i] < 0) {
521  nMax += 1;
522  lastDiscrete = discrete[i];
523  if (myPid == 0) {
524  cout << " ";
525  cout.width(4);
526  cout << i+1 << ". ";
527  cout.precision(8);
528  cout.setf(ios::scientific, ios::floatfield);
529  cout << continuous[i] << " " << discrete[i] << " ";
530  cout << "************** ********* ";
531  cout.precision(3);
532  cout << fabs(continuous[i]-discrete[i])/continuous[i] << endl;
533  }
534  }
535  else {
536  nMax += 1;
537  lastDiscrete = discrete[i];
538  if (myPid == 0) {
539  cout << " ";
540  cout.width(4);
541  cout << i+1 << ". ";
542  cout.precision(8);
543  cout.setf(ios::scientific, ios::floatfield);
544  cout << continuous[i] << " " << discrete[i] << " " << lambda[used[i]] << " ";
545  cout.precision(3);
546  cout << fabs(lambda[used[i]]-discrete[i])/discrete[i] << " ";
547  cout << fabs(continuous[i]-discrete[i])/continuous[i] << endl;
548  }
549  iCount += 1;
550  }
551  }
552 
553  delete[] used;
554 
555  return nMax;
556 
557 }
558 
559 
560 int CheckingTools::inputArguments(const int &numEigen, const Epetra_Operator *K,
561  const Epetra_Operator *M, const Epetra_Operator *P,
562  const Epetra_MultiVector &Q, const int &minSize) const {
563 
564  // Routine to check some arguments
565  //
566  // info = - 1 >> The stiffness matrix K has not been specified.
567  // info = - 2 >> The maps for the matrix K and the matrix M differ.
568  // info = - 3 >> The maps for the matrix K and the preconditioner P differ.
569  // info = - 4 >> The maps for the vectors and the matrix K differ.
570  // info = - 5 >> Q is too small for the number of eigenvalues requested.
571  // info = - 6 >> Q is too small for the computation parameters.
572  //
573 
574  int myPid = MyComm.MyPID();
575 
576  if (K == 0) {
577  if (myPid == 0)
578  cerr << "\n !!! The matrix K to analyze has not been specified !!! \n\n";
579  return -1;
580  }
581 
582  if (M) {
583  int mGlobal = (M->OperatorDomainMap()).NumGlobalElements();
584  int mLocal = (M->OperatorDomainMap()).NumMyElements();
585  int kGlobal = (K->OperatorDomainMap()).NumGlobalElements();
586  int kLocal = (K->OperatorDomainMap()).NumMyElements();
587  if ((mGlobal != kGlobal) || (mLocal != kLocal)) {
588  if (myPid == 0) {
589  cerr << endl;
590  cerr << " !!! The maps for the matrice K and the mass M are different !!!\n";
591  cerr << endl;
592  }
593  return -2;
594  }
595  }
596 
597  if (P) {
598  int pGlobal = (P->OperatorDomainMap()).NumGlobalElements();
599  int pLocal = (P->OperatorDomainMap()).NumMyElements();
600  int kGlobal = (K->OperatorDomainMap()).NumGlobalElements();
601  int kLocal = (K->OperatorDomainMap()).NumMyElements();
602  if ((pGlobal != kGlobal) || (pLocal != kLocal)) {
603  if (myPid == 0) {
604  cerr << endl;
605  cerr << " !!! The maps for the matrice K and the preconditioner P are different !!!\n";
606  cerr << endl;
607  }
608  return -3;
609  }
610  }
611 
612  if ((Q.MyLength() != (K->OperatorDomainMap()).NumMyElements()) ||
613  (Q.GlobalLength() != (K->OperatorDomainMap()).NumGlobalElements())) {
614  if (myPid == 0) {
615  cerr << "\n !!! The maps for the vectors and the matrix are different !!! \n\n";
616  }
617  return -4;
618  }
619 
620  if (Q.NumVectors() < numEigen) {
621  if (myPid == 0) {
622  cerr << endl;
623  cerr << " !!! The number of eigenvalues is too large for the space allocated !!! \n\n";
624  cerr << " The recommended size for " << numEigen << " eigenvalues is ";
625  cerr << minSize << endl;
626  cerr << endl;
627  }
628  return -5;
629  }
630 
631  if (Q.NumVectors() < minSize) {
632  if (myPid == 0) {
633  cerr << endl;
634  cerr << " !!! The space allocated is too small for the number of eigenvalues";
635  cerr << " and the size of blocks specified !!! \n";
636  cerr << " The recommended size for " << numEigen << " eigenvalues is ";
637  cerr << minSize << endl;
638  cerr << endl;
639  }
640  return -6;
641  }
642 
643  return 0;
644 
645 }
646 
647 
int ResetView(double *Values_in)
virtual int ApplyInverse(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const =0
void GESVD(const char JOBU, const char JOBVT, const int M, const int N, float *A, const int LDA, float *S, float *U, const int LDU, float *VT, const int LDVT, float *WORK, const int *LWORK, int *INFO) const
virtual const Epetra_Map & OperatorDomainMap() const =0
virtual int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const =0
void LAMCH(const char CMACH, float &T) const