Anasazi Version of the Day
Loading...
Searching...
No Matches
driver.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 <fstream>
20
21#include "Epetra_ConfigDefs.h"
22#include "Epetra_Map.h"
23#include "Epetra_MultiVector.h"
24
25#ifdef EPETRA_MPI
26#include "Epetra_MpiComm.h"
27#include "mpi.h"
28#else
29#include "Epetra_SerialComm.h"
30#endif
31
32#include "MyMemory.h"
33
34#include "ModalAnalysisSolver.h"
35
36#include "BRQMIN.h"
37#include "BlockDACG.h"
38#include "LOBPCG.h"
39#include "LOBPCG_light.h"
40#include "KnyazevLOBPCG.h"
41#include "ARPACKm3.h"
42#include "ModifiedARPACKm3.h"
43#include "Davidson.h"
44#include "JDPCG.h"
45
46#include "ModalProblem.h"
47#include "ModeLaplace1DQ1.h"
48#include "ModeLaplace1DQ2.h"
49#include "ModeLaplace2DQ1.h"
50#include "ModeLaplace2DQ2.h"
51#include "ModeLaplace3DQ1.h"
52#include "ModeLaplace3DQ2.h"
53
54#include "BlockPCGSolver.h"
55#include "AMGOperator.h"
56#include "MyIncompleteChol.h"
57
58#include <stdexcept>
59#include <Teuchos_Assert.hpp>
60
61const int LOBPCG_CHOL = 1;
62const int LOBPCG_LIGHT = 2;
63const int LOBPCG_AK_CHOL = 3;
64const int ARPACK_ORIG = 5;
65const int ARPACK_RESI = 6;
66const int GALDAVIDSON = 7;
67const int BRQMIN_CHOL = 9;
68const int DACG_CHOL = 11;
69const int JD_PCG = 13;
70
71const int NO_PREC = 0;
72const int AMG_POLYNOMIAL = 1;
73const int AMG_GAUSSSEIDEL = 2;
74const int INC_CHOL = 3;
75
76
77int main(int argc, char *argv[]) {
78
79 int i;
80 int myPid = 0;
81 int numProc = 1;
82
83#ifdef EPETRA_MPI
84 // Initialize MPI
85 MPI_Init(&argc,&argv);
86 MPI_Comm_size(MPI_COMM_WORLD, &numProc);
87 MPI_Comm_rank(MPI_COMM_WORLD, &myPid);
88 Epetra_MpiComm Comm( MPI_COMM_WORLD );
89#else
90 Epetra_SerialComm Comm;
91#endif
92
93 // Initialize the random number generator
94 srand((unsigned) time(0));
95
96 // Initialize memory counters
97 initMemCounters();
98
99 int dimension;
100 double Lx = 1.0, Ly = 1.0, Lz = 1.0;
101 int nX=0, nY=0, nZ=0;
102 int casePb = 0;
103 int algo = 0;
104 int precond = 0, param = 0;
105 int numEigen = 0;
106 int dimSearch = 0;
107 int numBlock = 1;
108 int maxIter = 0;
109 double tol = 0.0;
110 int maxIterCG = 0;
111 double tolCG = 0.0;
112 int verbose = 0;
113
114 bool paramStop = false;
115 for (i=0; i<numProc; ++i) {
116 Comm.Barrier();
117 if (myPid == i) {
118 ifstream fin("control.driver");
119 char buff[101];
120 TEUCHOS_TEST_FOR_EXCEPTION( !fin, std::runtime_error, "The input file 'control."
121 "driver' could not be opened." );
122 fin >> dimension; fin.getline(buff, 100);
123 switch (dimension) {
124 case 1:
125 fin >> Lx; fin.getline(buff, 100);
126 fin >> nX; fin.getline(buff, 100);
127 fin >> casePb; fin.getline(buff, 100);
128 break;
129 case 2:
130 fin >> Lx >> Ly; fin.getline(buff, 100);
131 fin >> nX >> nY; fin.getline(buff, 100);
132 fin >> casePb; fin.getline(buff, 100);
133 break;
134 case 3:
135 fin >> Lx >> Ly >> Lz; fin.getline(buff, 100);
136 fin >> nX >> nY >> nZ; fin.getline(buff, 100);
137 fin >> casePb; fin.getline(buff, 100);
138 break;
139 default:
140 paramStop = true;
141 }
142 fin >> algo; fin.getline(buff, 100);
143 fin >> precond; fin.getline(buff, 100);
144 fin >> param; fin.getline(buff, 100);
145 fin >> numEigen; fin.getline(buff, 100);
146 fin >> dimSearch; fin.getline(buff, 100);
147 fin >> numBlock; fin.getline(buff, 100);
148 fin >> maxIter; fin.getline(buff, 100);
149 fin >> tol; fin.getline(buff, 100);
150 fin >> maxIterCG; fin.getline(buff, 100);
151 fin >> tolCG; fin.getline(buff, 100);
152 fin >> verbose; fin.getline(buff, 100);
153 }
154 Comm.Barrier();
155 }
156
157 // Check the input parameters
158 switch (algo) {
159 case LOBPCG_CHOL:
160 case LOBPCG_LIGHT:
161 case LOBPCG_AK_CHOL:
162 case 4:
163 case ARPACK_ORIG:
164 case ARPACK_RESI:
165 case GALDAVIDSON:
166 case BRQMIN_CHOL:
167 case DACG_CHOL:
168 case JD_PCG:
169 break;
170 default:
171 paramStop = true;
172 break;
173 }
174
175 switch (precond) {
176 case NO_PREC:
177 case AMG_POLYNOMIAL:
178 case AMG_GAUSSSEIDEL:
179 case INC_CHOL:
180 break;
181 default:
182 paramStop = true;
183 break;
184 }
185
186 if ((dimension < 1) && (dimension > 3))
187 paramStop = true;
188 else {
189 if ((casePb != 1) && (casePb != 2))
190 paramStop = true;
191 }
192
193 if (paramStop == true) {
194 if (verbose*(myPid==0) > 0) {
195#ifdef EPETRA_MPI
196 cerr << "Usage: prun -n NP ./driver" << endl;
197#else
198 cerr << "Usage: ./driver.serial" << endl;
199#endif
200 cerr << endl;
201 cerr << "Input file: 'control.driver'" << endl;
202 cerr << endl;
203 cerr << "Example of input file" << endl;
204 cerr << endl;
205 cerr << "3 Space dimension (1, 2, 3)" << endl;
206 cerr << "1.0 2.0 3.0 Lx Ly Lz (Dimension of brick in each direction)" << endl;
207 cerr << "10 11 12 nX nY nZ (Number of elements in each direction)" << endl;
208 cerr << "1 Case Problem (1=Q1, 2=Q2)" << endl;
209 cerr << "1 Algorithm (1 .. 15)" << endl;
210 cerr << "1 Preconditioner (0 = None, 1 = AMG Poly, 2 = AMG GS)"
211 << endl;
212 cerr << "1 Parameter for preconditioner: AMG Poly. Deg."
213 << endl;
214 cerr << "10 Number of eigenpairs requested" << endl;
215 cerr << "5 Dimension of block size" << endl;
216 cerr << "4 Number of blocks (ONLY referenced by Davidson (7) and JD-PCG (13))"
217 << endl;
218 cerr << "1000 Maximum number of iterations for eigensolver" << endl;
219 cerr << "1e-06 Tolerance" << endl;
220 cerr << "1000 Maximum number of inner iterations (PCG, QMR)" << endl;
221 cerr << "1e-07 Tolerance for PCG solve (ONLY referenced in ARPACK)" << endl;
222 cerr << "1 Verbose level" << endl;
223 cerr << "----------------------------------------------------------------------" << endl;
224 cerr << endl;
225 cerr << "Eigensolver flags:" << endl;
226 cerr << " 1. LOBPCG (RBL & UH version) with Cholesky-based local eigensolver" << endl;
227 cerr << " 2. LOBPCG (light version) with Cholesky-based local eigensolver" << endl;
228 cerr << " 3. LOBPCG (AK version) with Cholesky-based local eigensolver" << endl;
229 cerr << " 5. ARPACK (original version)" << endl;
230 cerr << " 6. ARPACK (version with user-provided residual)" << endl;
231 cerr << " 7. Generalized Davidson (RBL & UH version)" << endl;
232 cerr << " 9. BRQMIN with Cholesky-based local eigensolver" << endl;
233 cerr << "11. Block DACG with Cholesky-based local eigensolver" << endl;
234 cerr << "13. JDCG (Notay's version of Jacobi-Davidson)" << endl;
235 cerr << endl;
236 cerr << "The dimension of search space corresponds to" << endl;
237 cerr << " * the block size for LOBPCG (1)" << endl;
238 cerr << " * NCV for ARPACK (5, 6)" << endl;
239 cerr << " * one block size for Generalized Davidson (7)" << endl;
240 cerr << " * the block size for BRQMIN (9)" << endl;
241 cerr << " * the block size for Block DACG (11)" << endl;
242 cerr << " * one block size for Jacobi-Davidson JDCG (13)" << endl;
243 cerr << endl;
244 }
245 // mfh 14 Jan 2011: Replaced "exit(1)" with "return 1" since this
246 // is the "main" routine. If you move this part of the code out
247 // of main(), change the line below accordingly.
248 return 1;
249 }
250
251 double highMem = currentSize();
252
253 ModalProblem *testCase;
254 if (dimension == 1) {
255 if (casePb == 1)
256 testCase = new ModeLaplace1DQ1(Comm, Lx, nX);
257 if (casePb == 2)
258 testCase = new ModeLaplace1DQ2(Comm, Lx, nX);
259 }
260 if (dimension == 2) {
261 if (casePb == 1)
262 testCase = new ModeLaplace2DQ1(Comm, Lx, nX, Ly, nY);
263 if (casePb == 2)
264 testCase = new ModeLaplace2DQ2(Comm, Lx, nX, Ly, nY);
265 }
266 if (dimension == 3) {
267 if (casePb == 1)
268 testCase = new ModeLaplace3DQ1(Comm, Lx, nX, Ly, nY, Lz, nZ);
269 if (casePb == 2)
270 testCase = new ModeLaplace3DQ2(Comm, Lx, nX, Ly, nY, Lz, nZ);
271 }
272
273 highMem = (highMem < currentSize()) ? currentSize() : highMem;
274
275 // Print some information on the problem to solve
276 if (verbose*(myPid==0) > 0) {
277 cout << endl;
278 testCase->problemInfo();
279 }
280
281 // Get the stiffness and mass matrices
282 const Epetra_Operator *K = testCase->getStiffness();
283 const Epetra_Operator *M = testCase->getMass();
284
285 // Get the map of the equations across processors
286 const Epetra_Map Map = K->OperatorDomainMap();
287 int localSize = Map.NumMyElements();
288 int globalSize = Map.NumGlobalElements();
289
290 // Get the first eigenvalue for the mass matrix
291 numEigen = (numEigen > globalSize) ? globalSize : numEigen;
292
293 double *globalWeight = 0;
294 double globalMassMin = 0.0;
295
296 if (dynamic_cast<ModeLaplace*>(testCase))
297 globalMassMin = dynamic_cast<ModeLaplace*>(testCase)->getFirstMassEigenValue();
298 else {
299 // Input( Comm, Operator, verbose level, # levels, smoother, parameter, coarse solver)
300 AMGOperator precML(Comm, M, 0, 10, 1, 3, 0);
301 BlockPCGSolver linMassSolver(Comm, M, 1e-06, 20);
302 linMassSolver.setPreconditioner(&precML);
303 ARPACKm3 eigMassSolver(Comm, &linMassSolver, 1e-03, globalSize);
304 double *lTmp = new double[6];
305 Epetra_MultiVector QQ(Map, 6);
306 QQ.Random();
307 int massNEV = eigMassSolver.solve(1, QQ, lTmp);
308
309 // FIXME (mfh 14 Jan 2011) I'm not sure if std::runtime_error is
310 // the right exception to throw. I'm just replacing exit(1) with
311 // an exception, as per Trilinos coding standards.
312 TEUCHOS_TEST_FOR_EXCEPTION( massNEV < 1, std::runtime_error,
313 "Error in the computation of smallest eigenvalue for "
314 "the mass matrix. Output information from eigensolver"
315 " = " << massNEV );
316 globalMassMin = lTmp[0];
317 delete[] lTmp;
318 }
319
320 // Note: The following definition of weight results from the definition
321 // of "Epetra_MultiVector::NormWeighted"
322 globalWeight = new double[localSize];
323 for (i = 0; i < localSize; ++i) {
324 globalWeight[i] = sqrt(globalMassMin/globalSize);
325 }
326
327 if (verbose*(myPid==0) > 0) {
328 cout << endl;
329 cout.precision(2);
330 cout.setf(ios::scientific, ios::floatfield);
331 cout << " Smallest eigenvalue for the mass matrix: " << globalMassMin << endl;
332 cout << endl;
333 }
334
335 // Define arrays for the eigensolver algorithm
336 int qSize;
337 switch (algo) {
338 case LOBPCG_CHOL:
339 case LOBPCG_LIGHT:
340 qSize = dimSearch + numEigen;
341 break;
342 case LOBPCG_AK_CHOL:
343 qSize = numEigen;
344 dimSearch = numEigen;
345 break;
346 case ARPACK_ORIG:
347 case ARPACK_RESI:
348 if (dimSearch <= numEigen)
349 dimSearch = 2*numEigen;
350 qSize = dimSearch;
351 break;
352 case GALDAVIDSON:
353 numBlock = (numBlock <= 0) ? 1 : numBlock;
354 qSize = dimSearch*(numBlock+1);
355 break;
356 case BRQMIN_CHOL:
357 qSize = dimSearch + numEigen;
358 break;
359 case DACG_CHOL:
360 qSize = dimSearch + numEigen;
361 break;
362 case JD_PCG:
363 numBlock = (numBlock <= 0) ? 1 : numBlock;
364 qSize = dimSearch*(numBlock+1);
365 break;
366 }
367
368 double *vQ = new (nothrow) double[qSize*localSize];
369 assert(vQ != 0);
370
371 double *lambda = new (nothrow) double[qSize];
372 assert(lambda != 0);
373
374 Epetra_MultiVector Q(View, Map, vQ, localSize, qSize);
375 Q.Random();
376
377 highMem = (highMem > currentSize()) ? highMem : currentSize();
378
379 char precLabel[100];
380 MyIncompleteChol *ICT = 0;
381 BlockPCGSolver *opStiffness = new BlockPCGSolver(Comm, K, tolCG, maxIterCG,
382 (verbose) ? verbose-1 : 0);
383 AMGOperator *precML = 0;
384 switch (precond) {
385 case NO_PREC:
386 opStiffness->setPreconditioner(0);
387 strcpy(precLabel, " No preconditioner");
388 break;
389 case AMG_POLYNOMIAL:
390 // Use AMG preconditioner with polynomial smoother
391 if (param < 1)
392 param = 2;
393 precML = new AMGOperator(Comm, K, verbose, 10, 1, param, 0);
394 opStiffness->setPreconditioner(precML);
395 strcpy(precLabel, " AMG with polynomial smoother");
396 break;
397 case AMG_GAUSSSEIDEL:
398 // Use AMG preconditioner with Gauss-Seidel smoother
399 precML = new AMGOperator(Comm, K, verbose, 10, 2, param, 0);
400 opStiffness->setPreconditioner(precML);
401 strcpy(precLabel, " AMG with Gauss-Seidel smoother");
402 break;
403 case INC_CHOL:
404 // Use incomplete Cholesky with no-fill in
405 Epetra_Operator *KOp = const_cast<Epetra_Operator*>(K);
406 if (dynamic_cast<Epetra_CrsMatrix*>(KOp)) {
407 ICT = new MyIncompleteChol(Comm, KOp, Epetra_MinDouble, param);
408 }
409 else {
410 cerr << endl;
411 cerr << " !!! The incomplete Cholesky factorization can not be done !!!\n";
412 cerr << " !!! No preconditioner is used !!!\n";
413 cerr << endl;
414 }
415 opStiffness->setPreconditioner(ICT);
416 if (ICT)
417 strcpy(precLabel, " Incomplete Cholesky factorization");
418 break;
419 }
420
421 // Define the GeneralEigenSolver object
422 ModalAnalysisSolver *mySolver;
423
424 switch (algo) {
425 case LOBPCG_CHOL:
426 mySolver = new LOBPCG(Comm, opStiffness, M, opStiffness->getPreconditioner(),
427 dimSearch, tol, maxIter, verbose, globalWeight);
428 break;
429 case LOBPCG_LIGHT:
430 mySolver = new LOBPCG_light(Comm, opStiffness, M, opStiffness->getPreconditioner(),
431 dimSearch, tol, maxIter, verbose, globalWeight);
432 break;
433 case LOBPCG_AK_CHOL:
434 mySolver = new KnyazevLOBPCG(Comm, opStiffness, M, opStiffness->getPreconditioner(),
435 tol, maxIter, verbose, globalWeight);
436 break;
437 case ARPACK_ORIG:
438 mySolver = new ARPACKm3(Comm, opStiffness, M, tol, maxIter, verbose);
439 break;
440 case ARPACK_RESI:
441 mySolver = new ModifiedARPACKm3(Comm, opStiffness, M, tol, maxIter, verbose,
442 globalWeight);
443 break;
444 case GALDAVIDSON:
445 mySolver = new Davidson(Comm, opStiffness, M, opStiffness->getPreconditioner(),
446 dimSearch, numBlock, tol, maxIter, verbose, globalWeight);
447 break;
448 case BRQMIN_CHOL:
449 mySolver = new BRQMIN(Comm, opStiffness, M, opStiffness->getPreconditioner(),
450 dimSearch, tol, maxIter, verbose, globalWeight);
451 break;
452 case DACG_CHOL:
453 mySolver = new BlockDACG(Comm, opStiffness, M, opStiffness->getPreconditioner(),
454 dimSearch, tol, maxIter, verbose, globalWeight);
455 break;
456 case JD_PCG:
457 mySolver = new JDPCG(Comm, opStiffness, M, opStiffness->getPreconditioner(),
458 dimSearch, numBlock, tol, maxIter, maxIterCG, verbose, globalWeight);
459 break;
460 }
461
462 // Solve the eigenproblem
463 int knownEV = mySolver->solve(numEigen, Q, lambda);
464
465 // Output information on simulation
466
467 if (knownEV < 0) {
468 if (myPid == 0) {
469 cerr << endl;
470 cerr << " !!! The eigensolver exited with error " << knownEV << " !!! " << endl;
471 cerr << endl;
472 }
473 } // if (knownEV < 0)
474 else {
475
476 if (verbose*(myPid == 0) > 1) {
477 cout << endl;
478 cout << " ---------------------------------------------------- \n";
479 cout << " History of Computation \n";
480 cout << " ---------------------------------------------------- \n";
481 cout << endl;
482 mySolver->algorithmInfo();
483 cout << " Preconditioner: " << precLabel << endl;
484 cout << endl;
485 testCase->problemInfo();
486 cout << " Number of computed eigenmodes: " << knownEV << endl;
487 mySolver->historyInfo();
488 } // if (verbose*(myPid == 0) > 1)
489
490 // Eigenpairs accuracy
491 if (knownEV > 0) {
492 int nb = (knownEV > numEigen) ? numEigen : knownEV;
493 Epetra_MultiVector copyQ(View, Q, 0, nb);
494 if (myPid == 0) {
495 cout << endl;
496 cout << " ---------------------------------------------------- \n";
497 cout << " Eigenpairs accuracy \n";
498 cout << " ---------------------------------------------------- \n";
499 cout << endl;
500 mySolver->algorithmInfo();
501 cout << " Preconditioner: " << precLabel << endl;
502 cout << endl;
503 testCase->problemInfo();
504 cout << " Number of computed eigenmodes: " << copyQ.NumVectors() << endl;
505 cout.precision(2);
506 cout.setf(ios::scientific, ios::floatfield);
507 cout << " Tolerance on residuals: " << tol << endl;
508 cout << endl;
509 cout << " Smallest eigenvalue for the mass matrix: " << globalMassMin << endl;
510 cout << endl;
511 } // if (myPid == 0)
512 testCase->eigenCheck(copyQ, lambda, globalWeight);
513 }
514
515 // Print out statistics: memory, time
516 if (myPid == 0) {
517 cout << endl;
518 cout << " ---------------------------------------------------- \n";
519 cout << " Summary of statistics \n";
520 cout << " ---------------------------------------------------- \n";
521 cout << endl;
522 mySolver->algorithmInfo();
523 cout << " Preconditioner: " << precLabel << endl;
524 cout << endl;
525 testCase->problemInfo();
526 cout << " Number of computed eigenmodes: " << knownEV << endl;
527 cout.precision(2);
528 cout.setf(ios::scientific, ios::floatfield);
529 cout << " Tolerance on residuals: " << tol << endl;
530 if ((algo == ARPACK_ORIG) || (algo == ARPACK_RESI)) {
531 cout << " Size of Search Space: " << dimSearch << endl;
532 cout << endl;
533 cout.precision(2);
534 cout.setf(ios::scientific, ios::floatfield);
535 cout << " Tolerance on PCG solves: " << tolCG << endl;
536 cout << endl;
537 cout << " Minimum number of PCG iterations per solve: ";
538 cout << opStiffness->getMinIter() << endl;
539 cout.setf(ios::fixed, ios::floatfield);
540 cout << " Average number of PCG iterations per solve: ";
541 cout << opStiffness->getAvgIter() << endl;
542 cout << " Maximum number of PCG iterations per solve: ";
543 cout << opStiffness->getMaxIter() << endl;
544 }
545 cout << endl;
546 if (precond == AMG_POLYNOMIAL) {
547 cout << " Number of levels for AMG preconditioner: ";
548 cout << precML->getAMG_NLevels() << endl;
549 cout << " Polynomial degree of AMG preconditioner: " << param << endl;
550 cout << endl;
551 }
552 if (precond == AMG_GAUSSSEIDEL) {
553 cout << " Number of levels for AMG preconditioner: ";
554 cout << precML->getAMG_NLevels() << endl;
555 cout << endl;
556 }
557 if ((precond == INC_CHOL) && (ICT)) {
558 cout << " Level of fill for incomplete Cholesky factorisation: ";
559 cout << param << endl;
560 cout << endl;
561 }
562 cout << " Number of processors: " << numProc << endl;
563 cout << endl;
564 } // if (myPid == 0)
565
566 // Memory
567 double maxHighMem = 0.0;
568 Comm.MaxAll(&highMem, &maxHighMem, 1);
569 if (myPid == 0) {
570 cout << " --- Memory ---\n";
571 cout << endl;
572 cout.precision(2);
573 cout.setf(ios::fixed, ios::floatfield);
574 cout << " High water mark in set-up = (EST) ";
575 cout << maxHighMem << " MB\n";
576 cout << endl;
577 } // if (myPid == 0)
578
579 testCase->memoryInfo();
580
581 if (myPid == 0) {
582 cout.precision(2);
583 cout.setf(ios::fixed, ios::floatfield);
584 cout << " Memory requested per processor for eigenvectors = (EST) ";
585 cout << Q.GlobalLength()*numEigen*sizeof(double)/1024.0/1024.0/numProc;
586 cout << " MB\n";
587 cout << endl;
588 cout << " Memory requested per processor for working space = (EST) ";
589 cout << Q.GlobalLength()*(Q.NumVectors()-numEigen)*sizeof(double)/1024.0/1024.0/numProc;
590 cout << " MB\n";
591 cout << endl;
592 } // if (myPid == 0)
593
594 mySolver->memoryInfo();
595
596 mySolver->operationInfo();
597
598 mySolver->timeInfo();
599
600 } // if (knownEV < 0)
601
602 // Release all objects
603 delete opStiffness;
604 delete ICT;
605 delete precML;
606 delete mySolver;
607
608 delete[] lambda;
609 delete[] vQ;
610 delete[] globalWeight;
611
612 delete testCase;
613
614#ifdef EPETRA_MPI
615 MPI_Finalize() ;
616#endif
617
618 return 0;
619
620}