MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
constrained_generalized_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_generalized_hermitian_eigen_solver_h__
21 #define __mast_slepc_constrained_generalized_hermitian_eigen_solver_h__
22 
23 // C++ includes
24 #include <iomanip>
25 
26 // MAST includes
28 #include <mast/base/exceptions.hpp>
29 
30 // Eigen includes
31 #include <Eigen/Eigenvalues>
32 
33 
34 namespace MAST {
35 namespace Solvers {
36 namespace EigenWrapper {
37 
38 template <typename ScalarType,
39  typename EigenSolverType,
40  typename MatType,
41  typename VectorType>
43 
44 public:
45 
46  using scalar_t = ScalarType;
47 
51  ConstrainedGeneralizedHermitianEigenSolver(const std::vector<uint_t> &dofs):
52  _dofs (dofs),
53  _initialized (false),
54  _n (0) { }
55 
57 
59  inline ScalarType eig(uint_t i) {
60 
61  Assert0(_initialized, "solver not initialized");
62  Assert2(i < _n,
63  i, _n,
64  "Eigenvalue index must be less than matrix size");
65 
66  return _solver.eigenvalues()(i);
67  }
68 
69 
76  inline void getEigenVector(uint_t i,
77  VectorType &x) {
78 
79  Assert0(_initialized, "solver not initialized");
80  Assert2(i < _n,
81  i, _n,
82  "Eigenvalue index must be less than matrix size");
83 
84  Assert2(x.size() == _n,
85  x.size(), _n,
86  "Vector must have dimension of original matrix");
87 
88 
89  x.setZero();
90 
91  for (uint_t j=0; j<_dofs.size(); j++) {
92  x(_dofs[j]) = _solver.eigenvectors().col(i)(j);
93  }
94  }
95 
99  inline void solve(MatType &A_mat,
100  MatType &B_mat,
101  bool computeEigenvectors) {
102 
103  Assert0(!_initialized, "solver already initialized");
104 
105  Assert2(A_mat.rows() == A_mat.cols(),
106  A_mat.rows(), A_mat.cols(),
107  "Matrix must be square");
108  Assert2(B_mat.rows() == B_mat.cols(),
109  B_mat.rows(), B_mat.cols(),
110  "Matrix must be square");
111  Assert2(A_mat.rows() == B_mat.rows(),
112  A_mat.rows(), B_mat.rows(),
113  "Matrices must have same dimensions");
114 
115  _n = A_mat.rows();
116 
117  // initialize the matrices
118  _init_sub_matrices(A_mat, B_mat, _A_sub, _B_sub);
119 
120  // create the solver context
121  if (computeEigenvectors)
122  _solver.compute(_A_sub, _B_sub, Eigen::ComputeEigenvectors|Eigen::Ax_lBx);
123  else
124  _solver.compute(_A_sub, _B_sub, Eigen::EigenvaluesOnly);
125 
126  _initialized = true;
127  }
128 
129 
137  inline scalar_t sensitivity_solve(MatType &B,
138  MatType &A_sens,
139  MatType &B_sens,
140  uint_t i) {
141 
142  VectorType
143  v1 = VectorType::Zero(_n);
144 
145  this->getEigenVector(i, v1);
146 
147  scalar_t
148  eig = this->eig(i);
149 
150  eig =
151  v1.dot( (A_sens * v1) - (eig * B_sens * v1) )/ // numerator
152  v1.dot(B*v1); // denominator
153 
154  return eig;
155  }
156 
157 
158 protected:
159 
160  inline void
161  _init_sub_matrices(const Eigen::Matrix<scalar_t, Eigen::Dynamic, Eigen::Dynamic> &A,
162  const Eigen::Matrix<scalar_t, Eigen::Dynamic, Eigen::Dynamic> &B,
163  Eigen::Matrix<scalar_t, Eigen::Dynamic, Eigen::Dynamic> &A_sub,
164  Eigen::Matrix<scalar_t, Eigen::Dynamic, Eigen::Dynamic> &B_sub) {
165 
166  Assert0(!_initialized, "solver already initialized");
167 
168  A_sub.setZero(_dofs.size(), _dofs.size());
169  B_sub.setZero(_dofs.size(), _dofs.size());
170 
171  for (uint_t i=0; i<_dofs.size(); i++) {
172  for (uint_t j=0; j<_dofs.size(); j++) {
173  A_sub(i, j) = A(_dofs[i], _dofs[j]);
174  B_sub(i, j) = B(_dofs[i], _dofs[j]);
175  }
176  }
177  }
178 
179 
180  const std::vector<uint_t> &_dofs;
182  int _n;
183  MatType _A_sub;
184  MatType _B_sub;
185  EigenSolverType _solver;
186 };
187 
188 } // namespace EigenWrapper
189 } // namespace Solvers
190 } // namespace MAST
191 
192 #endif // __mast_slepc_constrained_generalized_hermitian_eigen_solver_h__
193 
void solve(MatType &A_mat, MatType &B_mat, bool computeEigenvectors)
method for eigenvalue problems
scalar_t sensitivity_solve(MatType &B, MatType &A_sens, MatType &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...
void _init_sub_matrices(const Eigen::Matrix< scalar_t, Eigen::Dynamic, Eigen::Dynamic > &A, const Eigen::Matrix< scalar_t, Eigen::Dynamic, Eigen::Dynamic > &B, Eigen::Matrix< scalar_t, Eigen::Dynamic, Eigen::Dynamic > &A_sub, Eigen::Matrix< scalar_t, Eigen::Dynamic, Eigen::Dynamic > &B_sub)
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
unsigned int uint_t
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
ConstrainedGeneralizedHermitianEigenSolver(const std::vector< uint_t > &dofs)
dofs is the vector of unconstrained degrees of freedom on the local rank.