MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
constrained_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_constrained_hermitian_eigen_solver_h__
21 #define __mast_slepc_constrained_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 
46  const std::vector<PetscInt> &dofs,
47  EPSProblemType type):
48  _comm (comm),
49  _dofs (dofs),
50  _initialized (false),
51  _n (0),
52  _n_converged (0),
53  _type (type),
54  _A_sub (nullptr),
55  _B_sub (nullptr) { }
56 
58 
59  if (_initialized) {
60 
61  EPSDestroy(&_eps);
62  ISDestroy(&_dof_indices);
63  MatDestroy(&_A_sub);
64  if (_B_sub)
65  MatDestroy(&_B_sub);
66  }
67  }
68 
70  inline unsigned int n_converged() {
71 
72  Assert0(_initialized, "solver not initialized");
73 
74  return _n_converged;
75  }
76 
77 
79  inline real_t eig(uint_t i) {
80 
81  Assert0(_initialized, "solver not initialized");
83  i, _n_converged,
84  "Eigenvalue index must be less than n_converged");
85 
86  real_t
87  re = 0.,
88  im = 0.;
89  EPSGetEigenvalue(_eps, i, &re, &im);
90 
91  // assuming that im == 0 for Hermitian problem
92  return re;
93  }
94 
95 
102  inline void getEigenPair(uint_t i,
103  real_t &eig,
104  Vec x) {
105 
106  Assert0(_initialized, "solver not initialized");
107  Assert2(i < _n_converged,
108  i, _n_converged,
109  "Eigenvalue index must be less than n_converged");
110 
111 
112  VecZeroEntries(x);
113 
114  Vec vr, vi;
115  MatCreateVecs(_A_sub, &vr, PETSC_NULL);
116  MatCreateVecs(_A_sub, &vi, PETSC_NULL);
117 
118  eig = 0.;
119 
120  real_t
121  im = 0.;
122 
123  EPSGetEigenpair(_eps, i, &eig, &im, vr, vi);
124 
125  // now copy the vector to the global vector x
126  PetscScalar *vals = nullptr;
127  VecGetArray(vr, &vals);
128  VecSetValues(x, _dofs.size(), _dofs.data(), vals, INSERT_VALUES);
129  VecRestoreArray(vr, &vals);
130 
131  // assuming that the imaginary componet of vector will be zero for
132  // generalized Hermitian problem
133  VecDestroy(&vr);
134  VecDestroy(&vi);
135  }
136 
140  inline void solve(Mat A_mat,
141  Mat *B_mat,
142  uint_t nev,
143  EPSWhich spectrum,
144  bool computeEigenvectors) {
145 
146  Assert0(!_initialized, "solver already initialized");
147 
148  PetscInt
149  m = 0,
150  n = 0;
151 
152  MatGetSize(A_mat, &m, &n);
153 
154  Assert2(m == n, m, n, "Matrix must be square");
155 
156  if (B_mat) {
157 
158  PetscInt
159  m2 = 0,
160  n2 = 0;
161 
162  MatGetSize(*B_mat, &m2, &n2);
163 
164  Assert0(_type == EPS_GHEP,
165  "Eigensolver type must be Generalized Hermitian");
166  Assert2(m==m2 && n==n2, m2, n2, "A and B must be same size");
167  }
168 
169  // initialize the matrices
170  _init_sub_matrices(A_mat, B_mat);
171 
172  // create the solver context
173  EPSCreate(_comm, &_eps);
174 
175  if (!B_mat) {
176 
177  EPSSetOperators(_eps, _A_sub, PETSC_NULL);
178  EPSSetProblemType(_eps, _type);
179 
180  Assert0(_type == EPS_HEP || _type == EPS_NHEP, "Invalid EPS type");
181  }
182  else {
183 
184  EPSSetOperators(_eps, _A_sub, _B_sub);
185  EPSSetProblemType(_eps, _type);
186 
187  Assert0(_type == EPS_GHEP || _type == EPS_GNHEP, "Invalid EPS type");
188  }
189 
190  if (spectrum == EPS_LARGEST_MAGNITUDE)
191  EPSSetWhichEigenpairs(_eps, EPS_LARGEST_MAGNITUDE);
192  else if (spectrum == EPS_SMALLEST_MAGNITUDE)
193  EPSSetWhichEigenpairs(_eps, EPS_SMALLEST_MAGNITUDE);
194  else if (spectrum == EPS_LARGEST_IMAGINARY)
195  EPSSetWhichEigenpairs(_eps, EPS_LARGEST_IMAGINARY);
196  else if (spectrum == EPS_SMALLEST_IMAGINARY)
197  EPSSetWhichEigenpairs(_eps, EPS_SMALLEST_IMAGINARY);
198  else if (spectrum == EPS_LARGEST_REAL)
199  EPSSetWhichEigenpairs(_eps, EPS_LARGEST_REAL);
200  else if (spectrum == EPS_SMALLEST_REAL)
201  EPSSetWhichEigenpairs(_eps, EPS_SMALLEST_REAL);
202  else
203  Assert0(false, "Invalid spectrum type");
204 
205  EPSSetDimensions(_eps, nev, PETSC_DEFAULT, PETSC_DEFAULT);
206  EPSSetFromOptions(_eps);
207  EPSSolve(_eps);
208  EPSGetConverged(_eps, &_n_converged);
209 
210  _initialized = true;
211  }
212 
213 
221  inline real_t sensitivity_solve(Mat B,
222  Mat A_sens,
223  Mat *B_sens,
224  uint_t i) {
225 
226  Vec v1, v2, v3;
227  MatCreateVecs(B, &v1, PETSC_NULL);
228  MatCreateVecs(B, &v2, PETSC_NULL);
229  MatCreateVecs(B, &v3, PETSC_NULL);
230 
231  real_t
232  eig = 0.,
233  num = 0.,
234  denom = 0.;
235 
236  this->getEigenPair(i, eig, v1);
237 
238  // compute the denominator x^T B x
239  MatMult(B, v1, v2);
240  VecDot(v1, v2, &denom);
241 
242  // numerator dA/dp x
243  MatMult(A_sens, v1, v2);
244 
245  if (B_sens) {
246  // numerator dB/dp x
247  MatMult(*B_sens, v1, v3);
248 
249  // dA/dp x - eig dB/dp x
250  VecAXPY(v2, -eig, v3);
251  }
252  else
253  // dA/dp x - eig x
254  VecAXPY(v2, -eig, v1);
255 
256  VecDot(v1, v2, &num);
257 
258  return num/denom;
259  }
260 
261 
263 
264  real_t error;
265 
266  for (uint_t i=0; i<_n_converged; i++) {
267 
268  EPSComputeError(_eps, i, EPS_ERROR_RELATIVE, &error);
269  std::cout
270  << std::setw(10) << i
271  << std::setw(30) << this->eig(i)
272  << std::setw(30) << error << std::endl;
273  }
274 
275  }
276 
277 protected:
278 
279  inline void _init_sub_matrices(Mat A_mat,
280  Mat *B_mat) {
281 
282  Assert0(!_initialized, "solver already initialized");
283 
284  ISCreateGeneral(_comm, _dofs.size(), _dofs.data(), PETSC_USE_POINTER, &_dof_indices);
285  MatCreateSubMatrix(A_mat, _dof_indices, _dof_indices,
286 #if (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR > 7)
287  MAT_INITIAL_MATRIX,
288 #endif
289  &_A_sub);
290 
291  if (B_mat)
292  MatCreateSubMatrix(*B_mat, _dof_indices, _dof_indices,
293 #if (PETSC_VERSION_MAJOR == 3) && (PETSC_VERSION_MINOR > 7)
294  MAT_INITIAL_MATRIX,
295 #endif
296  &_B_sub);
297  }
298 
299 
300  MPI_Comm _comm;
301  const std::vector<PetscInt> &_dofs;
304  EPSProblemType _type;
306  Mat _A_sub;
307  Mat _B_sub;
308  EPS _eps;
309 };
310 
311 } // namespace SLEPcWrapper
312 } // namespace Solvers
313 } // namespace MAST
314 
315 #endif // __mast_slepc_constrained_hermitian_eigen_solver_h__
316 
ConstrainedHermitianEigenSolver(MPI_Comm comm, const std::vector< PetscInt > &dofs, EPSProblemType type)
dofs is the vector of unconstrained degrees of freedom on the local rank.
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 Dimension of the matrices B, A_sens and B_sens is equal t...
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
unsigned int uint_t
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
double real_t