MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
hermitian_eigen_solver.hpp
Go to the documentation of this file.
1 /*
2 * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3 * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 
20 #ifndef __mast_slepc_hermitian_eigen_solver_h__
21 #define __mast_slepc_hermitian_eigen_solver_h__
22 
23 // C++ includes
24 #include <iomanip>
25 
26 // MAST includes
28 #include <mast/base/exceptions.hpp>
29 
30 // SLEPc includes
31 #include <slepc.h>
32 
33 
34 namespace MAST {
35 namespace Solvers {
36 namespace SLEPcWrapper {
37 
39 
40 public:
41 
42  HermitianEigenSolver(MPI_Comm comm,
43  EPSProblemType type):
44  _comm (comm),
45  _initialized (false),
46  _n (0),
47  _n_converged (0),
48  _type(type) { }
49 
51 
52  if (_initialized)
53  EPSDestroy(&_eps);
54  }
55 
57  inline unsigned int n_converged() {
58 
59  Assert0(_initialized, "solver not initialized");
60 
61  return _n_converged;
62  }
63 
64 
66  inline real_t eig(uint_t i) {
67 
68  Assert0(_initialized, "solver not initialized");
70  i, _n_converged,
71  "Eigenvalue index must be less than n_converged");
72 
73  real_t
74  re = 0.,
75  im = 0.;
76  EPSGetEigenvalue(_eps, i, &re, &im);
77 
78  // assuming that im == 0 for Hermitian problem
79  return re;
80  }
81 
82 
84  inline void getEigenPair(uint_t i,
85  real_t &eig,
86  Vec x) {
87 
88  Assert0(_initialized, "solver not initialized");
90  i, _n_converged,
91  "Eigenvalue index must be less than n_converged");
92 
93 
94  VecZeroEntries(x);
95 
96  Vec vi;
97  VecDuplicate(x, &vi);
98 
99  eig = 0.;
100 
101  real_t
102  im = 0.;
103 
104  EPSGetEigenpair(_eps, i, &eig, &im, x, vi);
105 
106  // assuming that the imaginary componet of vector will be zero for
107  // generalized Hermitian problem
108  VecDestroy(&vi);
109  }
110 
114  inline void solve(Mat A_mat,
115  Mat *B_mat,
116  uint_t nev,
117  EPSWhich spectrum,
118  bool computeEigenvectors) {
119 
120  Assert0(!_initialized, "solver already initialized");
121 
122  PetscInt
123  m = 0,
124  n = 0;
125 
126  MatGetSize(A_mat, &m, &n);
127 
128  Assert2(m == n, m, n, "Matrix must be square");
129 
130  if (B_mat) {
131 
132  PetscInt
133  m2 = 0,
134  n2 = 0;
135 
136  MatGetSize(*B_mat, &m2, &n2);
137 
138  Assert0(_type == EPS_GHEP,
139  "Eigensolver type must be Generalized Hermitian");
140  Assert2(m==m2 && n==n2, m2, n2, "A and B must be same size");
141  }
142 
143  EPSCreate(_comm, &_eps);
144 
145  if (!B_mat) {
146 
147  EPSSetOperators(_eps, A_mat, PETSC_NULL);
148  EPSSetProblemType(_eps, _type);
149 
150  Assert0(_type == EPS_HEP || _type == EPS_NHEP, "Invalid EPS type");
151  }
152  else {
153 
154  EPSSetOperators(_eps, A_mat, *B_mat);
155  EPSSetProblemType(_eps, _type);
156 
157  Assert0(_type == EPS_GHEP || _type == EPS_GNHEP, "Invalid EPS type");
158  }
159 
160  if (spectrum == EPS_LARGEST_MAGNITUDE)
161  EPSSetWhichEigenpairs(_eps, EPS_LARGEST_MAGNITUDE);
162  else if (spectrum == EPS_SMALLEST_MAGNITUDE)
163  EPSSetWhichEigenpairs(_eps, EPS_SMALLEST_MAGNITUDE);
164  else if (spectrum == EPS_LARGEST_IMAGINARY)
165  EPSSetWhichEigenpairs(_eps, EPS_LARGEST_IMAGINARY);
166  else if (spectrum == EPS_SMALLEST_IMAGINARY)
167  EPSSetWhichEigenpairs(_eps, EPS_SMALLEST_IMAGINARY);
168  else if (spectrum == EPS_LARGEST_REAL)
169  EPSSetWhichEigenpairs(_eps, EPS_LARGEST_REAL);
170  else if (spectrum == EPS_SMALLEST_REAL)
171  EPSSetWhichEigenpairs(_eps, EPS_SMALLEST_REAL);
172  else
173  Assert0(false, "Invalid spectrum type");
174 
175  EPSSetDimensions(_eps, nev, PETSC_DEFAULT, PETSC_DEFAULT);
176  EPSSetFromOptions(_eps);
177  EPSSolve(_eps);
178  EPSGetConverged(_eps, &_n_converged);
179 
180  _initialized = true;
181  }
182 
183 
189  inline real_t sensitivity_solve(Mat B,
190  Mat A_sens,
191  Mat *B_sens,
192  uint_t i) {
193 
194  Vec v1, v2, v3;
195  MatCreateVecs(B, &v1, PETSC_NULL);
196  MatCreateVecs(B, &v2, PETSC_NULL);
197  MatCreateVecs(B, &v3, PETSC_NULL);
198 
199  real_t
200  eig = 0.,
201  num = 0.,
202  denom = 0.;
203 
204  this->getEigenPair(i, eig, v1);
205 
206  // compute the denominator x^T B x
207  MatMult(B, v1, v2);
208  VecDot(v1, v2, &denom);
209 
210  // numerator dA/dp x
211  MatMult(A_sens, v1, v2);
212 
213  if (B_sens) {
214  // numerator dB/dp x
215  MatMult(*B_sens, v1, v3);
216 
217  // dA/dp x - eig dB/dp x
218  VecAXPY(v2, -eig, v3);
219  }
220  else
221  // dA/dp x - eig x
222  VecAXPY(v2, -eig, v1);
223 
224  VecDot(v1, v2, &num);
225 
226  return num/denom;
227  }
228 
229 
231 
232  real_t error;
233 
234  for (uint_t i=0; i<_n_converged; i++) {
235 
236  EPSComputeError(_eps, i, EPS_ERROR_RELATIVE, &error);
237  std::cout
238  << std::setw(10) << i
239  << std::setw(30) << this->eig(i)
240  << std::setw(30) << error << std::endl;
241  }
242 
243  }
244 
245 protected:
246 
247  MPI_Comm _comm;
250  EPSProblemType _type;
251  EPS _eps;
252 };
253 
254 } // namespace SLEPcWrapper
255 } // namespace Solvers
256 } // namespace MAST
257 
258 #endif // __mast_slepc_hermitian_eigen_solver_h__
259 
HermitianEigenSolver(MPI_Comm comm, EPSProblemType type)
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
unsigned int uint_t
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
real_t eig(uint_t i)
this method returns the eigen value
void solve(Mat A_mat, Mat *B_mat, uint_t nev, EPSWhich spectrum, bool computeEigenvectors)
method for eigenvalue problems
void getEigenPair(uint_t i, real_t &eig, Vec x)
this method returns the eigen pair
real_t sensitivity_solve(Mat B, Mat A_sens, Mat *B_sens, uint_t i)
compute the sensitivity of i th eigenvalue
double real_t