Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ModalTools.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 "ModalTools.h"
20 
21 
22 ModalTools::ModalTools(const Epetra_Comm &_Comm) :
23  callFortran(),
24  callBLAS(),
25  callLAPACK(),
26  MyComm(_Comm),
27  MyWatch(_Comm),
28  eps(0.0),
29  timeQtMult(0.0),
30  timeQMult(0.0),
31  timeProj_MassMult(0.0),
32  timeNorm_MassMult(0.0),
33  timeProj(0.0),
34  timeNorm(0.0),
35  numProj_MassMult(0),
36  numNorm_MassMult(0) {
37 
38  callLAPACK.LAMCH('E', eps);
39 
40 }
41 
42 
43 int ModalTools::makeSimpleLumpedMass(const Epetra_Operator *M, double *normWeight) const {
44 
45  // Return, in the array normWeight, weights value such that
46  // the function Epetra_MultiVector::NormWeighted computes
47  //
48  // || . || = ( N / ( 1^T M 1) )^{1/2} * || . ||_{2}
49  //
50  // where 1 is the vector with unit entries and N is the size of the problem
51  //
52  // normWeight : Array of double (length = # of unknowns on this processor)
53  // Contains at exit the weights
54  //
55  // Note: When M is 0, the function does not do anything
56 
57  if (M == 0)
58  return -1;
59 
60  int row = (M->OperatorDomainMap()).NumMyElements();
61 
62  double *zVal = new double[row];
63 
64  Epetra_Vector z(View, M->OperatorDomainMap(), zVal);
65  Epetra_Vector Mz(View, M->OperatorDomainMap(), normWeight);
66 
67  z.PutScalar(1.0);
68  M->Apply(z, Mz);
69 
70  delete[] zVal;
71 
72  int i;
73  double rho = 0.0;
74  for (i = 0; i < row; ++i)
75  rho += normWeight[i];
76 
77  normWeight[0] = rho;
78  MyComm.SumAll(normWeight, &rho, 1);
79 
80  int info = 0;
81  if (rho <= 0.0) {
82  info = -2;
83  if (MyComm.MyPID() == 0)
84  cerr << "\n !!! The mass matrix gives a negative mass: " << rho << " !!! \n\n";
85  return info;
86  }
87  rho = rho/(M->OperatorDomainMap()).NumGlobalElements();
88 
89  //
90  // Note that the definition of the weighted norm in Epetra forces this weight definition
91  // UH 09/03/03
92  //
93 
94  rho = sqrt(rho/(M->OperatorDomainMap()).NumGlobalElements());
95 
96  for (i = 0; i < row; ++i)
97  normWeight[i] = rho;
98 
99  return info;
100 
101 }
102 
103 
104 int ModalTools::massOrthonormalize(Epetra_MultiVector &X, Epetra_MultiVector &MX,
105  const Epetra_Operator *M, const Epetra_MultiVector &Q,
106  int howMany, int type, double *WS, double kappa) {
107 
108  // For the inner product defined by the operator M or the identity (M = 0)
109  // -> Orthogonalize X against Q
110  // -> Orthonormalize X
111  // Modify MX accordingly
112  // WS is used as a workspace (size: (# of columns in X)*(# of rows in X))
113  //
114  // Note that when M is 0, MX is not referenced
115  //
116  // Parameter variables
117  //
118  // X : Vectors to be transformed
119  //
120  // MX : Image of the block vector X by the mass matrix
121  //
122  // Q : Vectors to orthogonalize against
123  //
124  // howMany : Number of vectors of X to orthogonalized
125  // If this number is smaller than the total number of vectors in X,
126  // then it is assumed that the last "howMany" vectors are not orthogonal
127  // while the other vectors in X are othogonal to Q and orthonormal.
128  //
129  // type = 0 (default) > Performs both operations
130  // type = 1 > Performs Q^T M X = 0
131  // type = 2 > Performs X^T M X = I
132  //
133  // WS = Working space (default value = 0)
134  //
135  // kappa= Coefficient determining when to perform a second Gram-Schmidt step
136  // Default value = 1.5625 = (1.25)^2 (as suggested in Parlett's book)
137  //
138  // Output the status of the computation
139  //
140  // info = 0 >> Success.
141  //
142  // info > 0 >> Indicate how many vectors have been tried to avoid rank deficiency for X
143  //
144  // info = -1 >> Failure >> X has zero columns
145  // >> It happens when # col of X > # rows of X
146  // >> It happens when # col of [Q X] > # rows of X
147  // >> It happens when no good random vectors could be found
148 
149  int info = 0;
150 
151  // Orthogonalize X against Q
152  timeProj -= MyWatch.WallTime();
153  if (type != 2) {
154 
155  int xc = howMany;
156  int xr = X.MyLength();
157  int qc = Q.NumVectors();
158 
159  Epetra_MultiVector XX(View, X, X.NumVectors()-howMany, howMany);
160 
161  Epetra_MultiVector MXX(View, X.Map(), (M) ? MX.Values() + xr*(MX.NumVectors()-howMany)
162  : X.Values() + xr*(X.NumVectors()-howMany),
163  xr, howMany);
164 
165  // Perform the Gram-Schmidt transformation for a block of vectors
166 
167  // Compute the initial M-norms
168  double *oldDot = new double[xc];
169  MXX.Dot(XX, oldDot);
170 
171  // Define the product Q^T * (M*X)
172  double *qTmx = new double[2*qc*xc];
173 
174  // Multiply Q' with MX
175  timeQtMult -= MyWatch.WallTime();
176  callBLAS.GEMM('T', 'N', qc, xc, xr, 1.0, Q.Values(), xr, MXX.Values(), xr,
177  0.0, qTmx + qc*xc, qc);
178  MyComm.SumAll(qTmx + qc*xc, qTmx, qc*xc);
179  timeQtMult += MyWatch.WallTime();
180 
181  // Multiply by Q and substract the result in X
182  timeQMult -= MyWatch.WallTime();
183  callBLAS.GEMM('N', 'N', xr, xc, qc, -1.0, Q.Values(), xr, qTmx, qc,
184  1.0, XX.Values(), xr);
185  timeQMult += MyWatch.WallTime();
186 
187  // Update MX
188  if (M) {
189  if ((qc >= xc) || (WS == 0)) {
190  timeProj_MassMult -= MyWatch.WallTime();
191  M->Apply(XX, MXX);
192  timeProj_MassMult += MyWatch.WallTime();
193  numProj_MassMult += xc;
194  }
195  else {
196  Epetra_MultiVector MQ(View, Q.Map(), WS, Q.MyLength(), qc);
197  timeProj_MassMult -= MyWatch.WallTime();
198  M->Apply(Q, MQ);
199  timeProj_MassMult += MyWatch.WallTime();
200  numProj_MassMult += qc;
201  callBLAS.GEMM('N', 'N', xr, xc, qc, -1.0, MQ.Values(), xr, qTmx, qc,
202  1.0, MXX.Values(), xr);
203  } // if ((qc >= xc) || (WS == 0))
204  } // if (M)
205 
206  double newDot = 0.0;
207  int j;
208  for (j = 0; j < xc; ++j) {
209 
210  MXX(j)->Dot(*(XX(j)), &newDot);
211 
212  if (kappa*newDot < oldDot[j]) {
213 
214  // Apply another step of classical Gram-Schmidt
215  timeQtMult -= MyWatch.WallTime();
216  callBLAS.GEMM('T', 'N', qc, xc, xr, 1.0, Q.Values(), xr, MXX.Values(), xr,
217  0.0, qTmx + qc*xc, qc);
218  MyComm.SumAll(qTmx + qc*xc, qTmx, qc*xc);
219  timeQtMult += MyWatch.WallTime();
220 
221  timeQMult -= MyWatch.WallTime();
222  callBLAS.GEMM('N', 'N', xr, xc, qc, -1.0, Q.Values(), xr, qTmx, qc,
223  1.0, XX.Values(), xr);
224  timeQMult += MyWatch.WallTime();
225 
226  // Update MX
227  if (M) {
228  if ((qc >= xc) || (WS == 0)) {
229  timeProj_MassMult -= MyWatch.WallTime();
230  M->Apply(XX, MXX);
231  timeProj_MassMult += MyWatch.WallTime();
232  numProj_MassMult += xc;
233  }
234  else {
235  Epetra_MultiVector MQ(View, Q.Map(), WS, Q.MyLength(), qc);
236  timeProj_MassMult -= MyWatch.WallTime();
237  M->Apply(Q, MQ);
238  timeProj_MassMult += MyWatch.WallTime();
239  numProj_MassMult += qc;
240  callBLAS.GEMM('N', 'N', xr, xc, qc, -1.0, MQ.Values(), xr, qTmx, qc,
241  1.0, MXX.Values(), xr);
242  } // if ((qc >= xc) || (WS == 0))
243  } // if (M)
244 
245  break;
246  } // if (kappa*newDot < oldDot[j])
247  } // for (j = 0; j < xc; ++j)
248 
249  delete[] qTmx;
250  delete[] oldDot;
251 
252  } // if (type != 2)
253  timeProj += MyWatch.WallTime();
254 
255  // Orthonormalize X
256  timeNorm -= MyWatch.WallTime();
257  if (type != 1) {
258 
259  int j;
260  int xc = X.NumVectors();
261  int xr = X.MyLength();
262  int globalSize = X.GlobalLength();
263  int shift = (type == 2) ? 0 : Q.NumVectors();
264  int mxc = (M) ? MX.NumVectors() : X.NumVectors();
265 
266  bool allocated = false;
267  if (WS == 0) {
268  allocated = true;
269  WS = new double[xr];
270  }
271 
272  double *oldMXj = WS;
273  double *MXX = (M) ? MX.Values() : X.Values();
274  double *product = new double[2*xc];
275 
276  double dTmp;
277 
278  for (j = 0; j < howMany; ++j) {
279 
280  int numX = xc - howMany + j;
281  int numMX = mxc - howMany + j;
282 
283  // Put zero vectors in X when we are exceeding the space dimension
284  if (numX + shift >= globalSize) {
285  Epetra_Vector XXj(View, X, numX);
286  XXj.PutScalar(0.0);
287  if (M) {
288  Epetra_Vector MXXj(View, MX, numMX);
289  MXXj.PutScalar(0.0);
290  }
291  info = -1;
292  }
293 
294  int numTrials;
295  bool rankDef = true;
296  for (numTrials = 0; numTrials < 10; ++numTrials) {
297 
298  double *Xj = X.Values() + xr*numX;
299  double *MXj = MXX + xr*numMX;
300 
301  double oldDot = 0.0;
302  dTmp = callBLAS.DOT(xr, Xj, MXj);
303  MyComm.SumAll(&dTmp, &oldDot, 1);
304 
305  memcpy(oldMXj, MXj, xr*sizeof(double));
306 
307  if (numX > 0) {
308 
309  // Apply the first Gram-Schmidt
310 
311  callBLAS.GEMV('T', xr, numX, 1.0, X.Values(), xr, MXj, 0.0, product + xc);
312  MyComm.SumAll(product + xc, product, numX);
313  callBLAS.GEMV('N', xr, numX, -1.0, X.Values(), xr, product, 1.0, Xj);
314  if (M) {
315  if (xc == mxc) {
316  callBLAS.GEMV('N', xr, numX, -1.0, MXX, xr, product, 1.0, MXj);
317  }
318  else {
319  Epetra_Vector XXj(View, X, numX);
320  Epetra_Vector MXXj(View, MX, numMX);
321  timeNorm_MassMult -= MyWatch.WallTime();
322  M->Apply(XXj, MXXj);
323  timeNorm_MassMult += MyWatch.WallTime();
324  numNorm_MassMult += 1;
325  }
326  }
327 
328  double dot = 0.0;
329  dTmp = callBLAS.DOT(xr, Xj, MXj);
330  MyComm.SumAll(&dTmp, &dot, 1);
331 
332  if (kappa*dot < oldDot) {
333  callBLAS.GEMV('T', xr, numX, 1.0, X.Values(), xr, MXj, 0.0, product + xc);
334  MyComm.SumAll(product + xc, product, numX);
335  callBLAS.GEMV('N', xr, numX, -1.0, X.Values(), xr, product, 1.0, Xj);
336  if (M) {
337  if (xc == mxc) {
338  callBLAS.GEMV('N', xr, numX, -1.0, MXX, xr, product, 1.0, MXj);
339  }
340  else {
341  Epetra_Vector XXj(View, X, numX);
342  Epetra_Vector MXXj(View, MX, numMX);
343  timeNorm_MassMult -= MyWatch.WallTime();
344  M->Apply(XXj, MXXj);
345  timeNorm_MassMult += MyWatch.WallTime();
346  numNorm_MassMult += 1;
347  }
348  }
349  } // if (kappa*dot < oldDot)
350 
351  } // if (numX > 0)
352 
353  double norm = 0.0;
354  dTmp = callBLAS.DOT(xr, Xj, oldMXj);
355  MyComm.SumAll(&dTmp, &norm, 1);
356 
357  if (norm > oldDot*eps*eps) {
358  norm = 1.0/sqrt(norm);
359  callBLAS.SCAL(xr, norm, Xj);
360  if (M)
361  callBLAS.SCAL(xr, norm, MXj);
362  rankDef = false;
363  break;
364  }
365  else {
366  info += 1;
367  Epetra_Vector XXj(View, X, numX);
368  XXj.Random();
369  Epetra_Vector MXXj(View, MX, numMX);
370  if (M) {
371  timeNorm_MassMult -= MyWatch.WallTime();
372  M->Apply(XXj, MXXj);
373  timeNorm_MassMult += MyWatch.WallTime();
374  numNorm_MassMult += 1;
375  }
376  if (type == 0)
377  massOrthonormalize(XXj, MXXj, M, Q, 1, 1, WS, kappa);
378  } // if (norm > oldDot*eps*eps)
379 
380  } // for (numTrials = 0; numTrials < 10; ++numTrials)
381 
382  if (rankDef == true) {
383  Epetra_Vector XXj(View, X, numX);
384  XXj.PutScalar(0.0);
385  if (M) {
386  Epetra_Vector MXXj(View, MX, numMX);
387  MXXj.PutScalar(0.0);
388  }
389  info = -1;
390  break;
391  }
392 
393  } // for (j = 0; j < howMany; ++j)
394 
395  delete[] product;
396 
397  if (allocated == true) {
398  delete[] WS;
399  }
400 
401  } // if (type != 1)
402  timeNorm += MyWatch.WallTime();
403 
404  return info;
405 
406 }
407 
408 
409 void ModalTools::localProjection(int numRow, int numCol, int dotLength,
410  double *U, int ldU, double *MatV, int ldV,
411  double *UtMatV, int ldUtMatV, double *work) const {
412 
413  // This routine forms a projected matrix of a matrix Mat onto the subspace
414  // spanned by U and V
415  //
416  // numRow = Number of columns in U (or number of rows in U^T) (input)
417  //
418  // numCol = Number of columns in V (input)
419  //
420  // dotLength = Local length of vectors U and V (input)
421  //
422  // U = Array of double storing the vectors U (input)
423  //
424  // ldU = Leading dimension in U (input)
425  //
426  // MatV = Array of double storing the vectors Mat*V (input)
427  //
428  // ldMatV = Leading dimension in MatV (input)
429  //
430  // UtMatV = Array of double storing the projected matrix U^T * Mat * V (output)
431  //
432  // ldUtMatV = Leading dimension in UtMatV (input)
433  //
434  // work = Workspace (size >= 2*numRow*numCol)
435 
436  int j;
437  int offSet = numRow*numCol;
438 
439  callBLAS.GEMM('T', 'N', numRow, numCol, dotLength, 1.0, U, ldU, MatV, ldV,
440  0.0, work + offSet, numRow);
441  MyComm.SumAll(work + offSet, work, offSet);
442 
443  double *source = work;
444  double *result = UtMatV;
445  int howMany = numRow*sizeof(double);
446 
447  for (j = 0; j < numCol; ++j) {
448  memcpy(result, source, howMany);
449  // Shift the pointers
450  source = source + numRow;
451  result = result + ldUtMatV;
452  }
453 
454 }
455 
456 
457 int ModalTools::directSolver(int size, double *KK, int ldK, double *MM, int ldM,
458  int &nev, double *EV, int ldEV, double *theta, int verbose, int esType) const {
459 
460  // Routine for computing the first NEV generalized eigenpairs of the symmetric pencil (KK, MM)
461  //
462  // Parameter variables:
463  //
464  // size : Size of the matrices KK and MM
465  //
466  // KK : Symmetric "stiffness" matrix (Size = size x ldK)
467  //
468  // ldK : Leading dimension of KK (ldK >= size)
469  //
470  // MM : Symmetric Positive "mass" matrix (Size = size x ldM)
471  //
472  // ldM : Leading dimension of MM (ldM >= size)
473  //
474  // nev : Number of the smallest eigenvalues requested (input)
475  // Number of the smallest computed eigenvalues (output)
476  //
477  // EV : Array to store the eigenvectors (Size = nev x ldEV)
478  //
479  // ldEV : Leading dimension of EV (ldEV >= size)
480  //
481  // theta : Array to store the eigenvalues (Size = nev)
482  //
483  // verbose : Flag to print information on the computation
484  //
485  // esType : Flag to select the algorithm
486  //
487  // esType = 0 (default) Uses LAPACK routine (Cholesky factorization of MM)
488  // with deflation of MM to get orthonormality of
489  // eigenvectors (S^T MM S = I)
490  //
491  // esType = 1 Uses LAPACK routine (Cholesky factorization of MM)
492  // (no check of orthonormality)
493  //
494  // esType = 10 Uses LAPACK routine for simple eigenproblem on KK
495  // (MM is not referenced in this case)
496  //
497  // Note: The code accesses only the upper triangular part of KK and MM.
498  //
499  // Return the integer info on the status of the computation
500  //
501  // info = 0 >> Success
502  //
503  // info = - 20 >> Failure in LAPACK routine
504 
505  // Define local arrays
506 
507  double *kp = 0;
508  double *mp = 0;
509  double *tt = 0;
510 
511  double *U = 0;
512 
513  int i, j;
514  int rank = 0;
515  int info = 0;
516  int tmpI;
517 
518  int NB = 5 + callFortran.LAENV(1, "dsytrd", "u", size, -1, -1, -1, 6, 1);
519  int lwork = size*NB;
520  double *work = new double[lwork];
521 
522 // double tol = sqrt(eps);
523  double tol = 1e-12;
524 
525  switch (esType) {
526 
527  default:
528  case 0:
529 
530  // Use the Cholesky factorization of MM to compute the generalized eigenvectors
531 
532  // Define storage
533  kp = new double[size*size];
534  mp = new double[size*size];
535  tt = new double[size];
536  U = new double[size*size];
537 
538  if (verbose > 4)
539  cout << endl;
540 
541  // Copy KK & MM
542  tmpI = sizeof(double);
543  for (rank = size; rank > 0; --rank) {
544  memset(kp, 0, size*size*tmpI);
545  for (i = 0; i < rank; ++i) {
546  memcpy(kp + i*size, KK + i*ldK, (i+1)*tmpI);
547  memcpy(mp + i*size, MM + i*ldM, (i+1)*tmpI);
548  }
549  // Solve the generalized eigenproblem with LAPACK
550  info = 0;
551  callFortran.SYGV(1, 'V', 'U', rank, kp, size, mp, size, tt, work, lwork, &info);
552  // Treat error messages
553  if (info < 0) {
554  if (verbose > 0) {
555  cerr << endl;
556  cerr << " In DSYGV, argument " << -info << "has an illegal value.\n";
557  cerr << endl;
558  }
559  return -20;
560  }
561  if (info > 0) {
562  if (info > rank)
563  rank = info - rank;
564  continue;
565  }
566  // Check the quality of eigenvectors
567  for (i = 0; i < size; ++i) {
568  memcpy(mp + i*size, MM + i*ldM, (i+1)*tmpI);
569  for (j = 0; j < i; ++j)
570  mp[i + j*size] = mp[j + i*size];
571  }
572  callBLAS.GEMM('N', 'N', size, rank, size, 1.0, mp, size, kp, size, 0.0, U, size);
573  callBLAS.GEMM('T', 'N', rank, rank, size, 1.0, kp, size, U, size, 0.0, mp, rank);
574  double maxNorm = 0.0;
575  double maxOrth = 0.0;
576  for (i = 0; i < rank; ++i) {
577  for (j = i; j < rank; ++j) {
578  if (j == i) {
579  maxNorm = (fabs(mp[j+i*rank]-1.0) > maxNorm) ? fabs(mp[j+i*rank]-1.0) : maxNorm;
580  }
581  else {
582  maxOrth = (fabs(mp[j+i*rank]) > maxOrth) ? fabs(mp[j+i*rank]) : maxOrth;
583  }
584  }
585  }
586  if (verbose > 4) {
587  cout << " >> Local eigensolve >> Size: " << rank;
588  cout.precision(2);
589  cout.setf(ios::scientific, ios::floatfield);
590  cout << " Normalization error: " << maxNorm;
591  cout << " Orthogonality error: " << maxOrth;
592  cout << endl;
593  }
594  if ((maxNorm <= tol) && (maxOrth <= tol))
595  break;
596  } // for (rank = size; rank > 0; --rank)
597 
598  if (verbose > 4)
599  cout << endl;
600 
601  // Copy the eigenvectors
602  memset(EV, 0, nev*ldEV*tmpI);
603  nev = (rank < nev) ? rank : nev;
604  memcpy(theta, tt, nev*tmpI);
605  tmpI = rank*tmpI;
606  for (i = 0; i < nev; ++i) {
607  memcpy(EV + i*ldEV, kp + i*size, tmpI);
608  }
609 
610  break;
611 
612  case 1:
613 
614  // Use the Cholesky factorization of MM to compute the generalized eigenvectors
615 
616  // Define storage
617  kp = new double[size*size];
618  mp = new double[size*size];
619  tt = new double[size];
620 
621  // Copy KK & MM
622  tmpI = sizeof(double);
623  for (i = 0; i < size; ++i) {
624  memcpy(kp + i*size, KK + i*ldK, (i+1)*tmpI);
625  memcpy(mp + i*size, MM + i*ldM, (i+1)*tmpI);
626  }
627 
628  // Solve the generalized eigenproblem with LAPACK
629  info = 0;
630  callFortran.SYGV(1, 'V', 'U', size, kp, size, mp, size, tt, work, lwork, &info);
631 
632  // Treat error messages
633  if (info < 0) {
634  if (verbose > 0) {
635  cerr << endl;
636  cerr << " In DSYGV, argument " << -info << "has an illegal value.\n";
637  cerr << endl;
638  }
639  return -20;
640  }
641  if (info > 0) {
642  if (info > size)
643  nev = 0;
644  else {
645  if (verbose > 0) {
646  cerr << endl;
647  cerr << " In DSYGV, DPOTRF or DSYEV returned an error code (" << info << ").\n";
648  cerr << endl;
649  }
650  return -20;
651  }
652  }
653 
654  // Copy the eigenvectors
655  memcpy(theta, tt, nev*tmpI);
656  tmpI = size*tmpI;
657  for (i = 0; i < nev; ++i) {
658  memcpy(EV + i*ldEV, kp + i*size, tmpI);
659  }
660 
661  break;
662 
663  case 10:
664 
665  // Simple eigenproblem
666 
667  // Define storage
668  kp = new double[size*size];
669  tt = new double[size];
670 
671  // Copy KK
672  tmpI = sizeof(double);
673  for (i=0; i<size; ++i) {
674  memcpy(kp + i*size, KK + i*ldK, (i+1)*tmpI);
675  }
676 
677  // Solve the generalized eigenproblem with LAPACK
678  callFortran.SYEV('V', 'U', size, kp, size, tt, work, lwork, &info);
679 
680  // Treat error messages
681  if (info != 0) {
682  if (verbose > 0) {
683  cerr << endl;
684  if (info < 0)
685  cerr << " In DSYEV, argument " << -info << " has an illegal value\n";
686  else
687  cerr << " In DSYEV, the algorithm failed to converge (" << info << ").\n";
688  cerr << endl;
689  }
690  info = -20;
691  break;
692  }
693 
694  // Copy the eigenvectors
695  memcpy(theta, tt, nev*tmpI);
696  tmpI = size*tmpI;
697  for (i = 0; i < nev; ++i) {
698  memcpy(EV + i*ldEV, kp + i*size, tmpI);
699  }
700 
701  break;
702 
703  }
704 
705  // Clear the memory
706 
707  if (kp)
708  delete[] kp;
709  if (mp)
710  delete[] mp;
711  if (tt)
712  delete[] tt;
713  if (work)
714  delete[] work;
715  if (U)
716  delete[] U;
717 
718  return info;
719 
720 }
721 
722 
virtual const Epetra_Map & OperatorDomainMap() const =0
virtual int Apply(const Epetra_MultiVector &X, Epetra_MultiVector &Y) const =0
float DOT(const int N, const float *X, const float *Y, const int INCX=1, const int INCY=1) const