gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
eigenSolver.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include "eigenSolver.h"
7 #include "OS.h"
8 
9 #if defined(HAVE_SLEPC)
10 
11 #include <slepceps.h>
12 #if SLEPC_VERSION_RELEASE != 0 && \
13  (SLEPC_VERSION_MAJOR < 3 || \
14  (SLEPC_VERSION_MAJOR == 3 && SLEPC_VERSION_MINOR < 2))
15 #define EPSDestroy(e) EPSDestroy(*(e))
16 #endif
17 
18 void eigenSolver::_check(int ierr) const { CHKERRABORT(PETSC_COMM_WORLD, ierr); }
19 
20 eigenSolver::eigenSolver(dofManager<double> *manager, std::string A,
21  std::string B, bool hermitian)
22  : _sysA(0), _sysB(0), _hermitian(hermitian)
23 {
24  if(A.size()) {
25  _sysA = dynamic_cast<linearSystemPETSc<double> *>(manager->getLinearSystem(A));
26  if(!_sysA) Msg::Error("Could not find PETSc system '%s'", A.c_str());
27  }
28  if(B.size()) {
29  _sysB = dynamic_cast<linearSystemPETSc<double> *>(manager->getLinearSystem(B));
30  if(!_sysB) Msg::Error("Could not find PETSc system '%s'", B.c_str());
31  }
32 }
33 
35  linearSystemPETSc<double> *B, bool hermitian)
36  : _sysA(A), _sysB(B), _hermitian(hermitian)
37 {
38 }
39 
40 bool eigenSolver::solve(int numEigenValues, std::string which,
41  std::string method, double tolVal, int iterMax)
42 {
43  if(!_sysA) return false;
44  Mat A = _sysA->getMatrix();
45  Mat B = _sysB ? _sysB->getMatrix() : PETSC_NULL;
46 
47  PetscInt N, M;
48  _check(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
49  _check(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
50  _check(MatGetSize(A, &N, &M));
51 
52  PetscInt N2, M2;
53  if(_sysB) {
54  _check(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
55  _check(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
56  _check(MatGetSize(B, &N2, &M2));
57  }
58 
59  // generalized eigenvalue problem A x - \lambda B x = 0
60  EPS eps;
61  _check(EPSCreate(PETSC_COMM_WORLD, &eps));
62  _check(EPSSetOperators(eps, A, B));
63  if(_hermitian)
64  _check(EPSSetProblemType(eps, _sysB ? EPS_GHEP : EPS_HEP));
65  else
66  _check(EPSSetProblemType(eps, _sysB ? EPS_GNHEP : EPS_NHEP));
67 
68  // set some default options
69  _check(EPSSetDimensions(eps, numEigenValues, PETSC_DECIDE, PETSC_DECIDE));
70  _check(EPSSetTolerances(eps, tolVal, iterMax));
71  if(method == "krylovschur")
72  _check(EPSSetType(eps, EPSKRYLOVSCHUR));
73  else if(method == "arnoldi")
74  _check(EPSSetType(eps, EPSARNOLDI));
75  else if(method == "arpack")
76  _check(EPSSetType(eps, EPSARPACK));
77  else if(method == "power")
78  _check(EPSSetType(eps, EPSPOWER));
79  else{
80  Msg::Error("eigenSolver: method '%s' not available", method.c_str());
81  _check(EPSSetType(eps, EPSKRYLOVSCHUR));
82  }
83 
84  // override these options at runtime, petsc-style
85  _check(EPSSetFromOptions(eps));
86 
87  // force options specified directly as arguments
88  if(numEigenValues)
89  _check(EPSSetDimensions(eps, numEigenValues, PETSC_DECIDE, PETSC_DECIDE));
90  if(which == "smallest")
91  _check(EPSSetWhichEigenpairs(eps, EPS_SMALLEST_MAGNITUDE));
92  else if(which == "smallestReal")
93  _check(EPSSetWhichEigenpairs(eps, EPS_SMALLEST_REAL));
94  else if(which == "largest")
95  _check(EPSSetWhichEigenpairs(eps, EPS_LARGEST_MAGNITUDE));
96 
97  // print info
98 #if(SLEPC_VERSION_RELEASE == 0 || \
99  (SLEPC_VERSION_MAJOR > 3 || \
100  (SLEPC_VERSION_MAJOR == 3 && SLEPC_VERSION_MINOR >= 4)))
101  EPSType type;
102 #else
103  const EPSType type;
104 #endif
105  _check(EPSGetType(eps, &type));
106  Msg::Debug("SLEPc solution method: %s", type);
107 
108  PetscInt nev;
109  _check(EPSGetDimensions(eps, &nev, PETSC_NULL, PETSC_NULL));
110  Msg::Debug("SLEPc number of requested eigenvalues: %d", nev);
111  PetscReal tol;
112  PetscInt maxit;
113  _check(EPSGetTolerances(eps, &tol, &maxit));
114  Msg::Debug("SLEPc stopping condition: tol=%g, maxit=%d", tol, maxit);
115 
116  // solve
117  Msg::Info("SLEPc solving...");
118  double t1 = Cpu(), w1 = TimeOfDay();
119  _check(EPSSolve(eps));
120 
121  // check convergence
122  int its;
123  _check(EPSGetIterationNumber(eps, &its));
124  EPSConvergedReason reason;
125  _check(EPSGetConvergedReason(eps, &reason));
126  if(reason == EPS_CONVERGED_TOL) {
127  double t2 = Cpu(), w2 = TimeOfDay();
128  Msg::Debug("SLEPc converged in %d iterations (Wall %gs, CPU %gs)", its,
129  w2 - w1, t2 - t1);
130  }
131  else if(reason == EPS_DIVERGED_ITS)
132  Msg::Error("SLEPc diverged after %d iterations", its);
133  else if(reason == EPS_DIVERGED_BREAKDOWN)
134  Msg::Error("SLEPc generic breakdown in method");
135 #if(SLEPC_VERSION_MAJOR < 3 || \
136  (SLEPC_VERSION_MAJOR == 3 && SLEPC_VERSION_MINOR < 2))
137  else if(reason == EPS_DIVERGED_NONSYMMETRIC)
138  Msg::Error("The operator is nonsymmetric");
139 #endif
140 
141  // get number of converged approximate eigenpairs
142  PetscInt nconv;
143  _check(EPSGetConverged(eps, &nconv));
144  Msg::Debug("SLEPc number of converged eigenpairs: %d", nconv);
145 
146  // ignore additional eigenvalues if we get more than what we asked
147  if(nconv > nev) nconv = nev;
148 
149  if(nconv > 0) {
150  Vec xr, xi;
151 #if(PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR < 6)
152  _check(MatGetVecs(A, PETSC_NULL, &xr));
153  _check(MatGetVecs(A, PETSC_NULL, &xi));
154 #else
155  _check(MatCreateVecs(A, PETSC_NULL, &xr));
156  _check(MatCreateVecs(A, PETSC_NULL, &xi));
157 #endif
158  Msg::Debug(" Re[EigenValue] Im[EigenValue]"
159  " Relative error");
160  for(int i = 0; i < nconv; i++) {
161  PetscScalar kr, ki;
162  _check(EPSGetEigenpair(eps, i, &kr, &ki, xr, xi));
163  PetscReal error;
164 #if(PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR < 6)
165  _check(EPSComputeRelativeError(eps, i, &error));
166 #else
167  _check(EPSComputeError(eps, i, EPS_ERROR_RELATIVE, &error));
168 #endif
169 #if defined(PETSC_USE_COMPLEX)
170  PetscReal re = PetscRealPart(kr);
171  PetscReal im = PetscImaginaryPart(kr);
172 #else
173  PetscReal re = kr;
174  PetscReal im = ki;
175 #endif
176  Msg::Debug("EIG %03d %s%.16e %s%.16e %3.6e", i, (re < 0) ? "" : " ", re,
177  (im < 0) ? "" : " ", im, error);
178 
179  // store eigenvalues and eigenvectors
180  _eigenValues.push_back(std::complex<double>(re, im));
181  PetscScalar *tmpr, *tmpi;
182  _check(VecGetArray(xr, &tmpr));
183  _check(VecGetArray(xi, &tmpi));
184  std::vector<std::complex<double> > ev(N);
185  for(int i = 0; i < N; i++) {
186 #if defined(PETSC_USE_COMPLEX)
187  ev[i] = tmpr[i];
188 #else
189  ev[i] = std::complex<double>(tmpr[i], tmpi[i]);
190 #endif
191  }
192  _eigenVectors.push_back(ev);
193  }
194  _check(VecDestroy(&xr));
195  _check(VecDestroy(&xi));
196  }
197 
198  _check(EPSDestroy(&eps));
199 
200  if(reason == EPS_CONVERGED_TOL) {
201  Msg::Debug("SLEPc done");
202  return true;
203  }
204  else {
205  Msg::Warning("SLEPc failed");
206  return false;
207  }
208 }
209 
210 void eigenSolver::normalize_mode(std::vector<int> modeView, double scale)
211 {
212  Msg::Info("Normalize all eigenvectors");
213  for(std::size_t imode = 0; imode < modeView.size(); imode++) {
214  int i = modeView[imode];
215  double norm = 0.;
216  for(std::size_t j = 0; j < _eigenVectors[i].size(); j++) {
217  std::complex<double> val = _eigenVectors[i][j];
218  double normval = std::abs(val);
219  if(normval > norm) norm = normval;
220  }
221  if(norm == 0) {
222  Msg::Error("zero eigenvector");
223  return;
224  }
225  for(std::size_t j = 0; j < _eigenVectors[i].size(); j++) {
226  _eigenVectors[i][j] *= (scale / norm);
227  }
228  }
229 }
230 
231 #endif
eigenSolver.h
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
linearSystemPETSc
Definition: linearSystemPETSc.h:150
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
OS.h
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
norm
void norm(const double *vec, double *norm)
Definition: gmshLevelset.cpp:202
Cpu
double Cpu()
Definition: OS.cpp:366
dofManager< double >
eigenSolver::eigenSolver
eigenSolver(dofManager< double > *manager, std::string A, std::string B="", bool hermitian=false)
Definition: eigenSolver.h:67
eigenSolver::normalize_mode
void normalize_mode(std::vector< int > modeView, double scale=1.)
Definition: eigenSolver.h:85
dofManager::getLinearSystem
virtual linearSystem< dataMat > * getLinearSystem(std::string &name)
Definition: dofManager.h:628
eigenSolver::solve
bool solve(int=0, std::string="", std::string="", double=0, int=0)
Definition: eigenSolver.h:75
scale
static void scale(std::vector< double > &x, double s)
Definition: ConjugateGradients.cpp:21