KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
eigensystem_solver.h
Go to the documentation of this file.
1 /* KRATOS _ _ ____ _
2 // | | (_)_ __ ___ __ _ _ __/ ___| ___ | |_ _____ _ __ ___
3 // | | | | '_ \ / _ \/ _` | '__\___ \ / _ \| \ \ / / _ \ '__/ __|
4 // | |___| | | | | __/ (_| | | ___) | (_) | |\ V / __/ | \__ |
5 // |_____|_|_| |_|\___|\__,_|_| |____/ \___/|_| \_/ \___|_| |___/ Application
6 //
7 // Authors: Thomas Oberbichler
8 // Armin Geiser
9 */
10 
11 #if !defined(KRATOS_EIGENSYSTEM_SOLVER_H_INCLUDED)
12 #define KRATOS_EIGENSYSTEM_SOLVER_H_INCLUDED
13 
14 // External includes
15 #include <Eigen/Core>
16 #include <Eigen/Eigenvalues>
17 
18 // Project includes
19 #include "includes/define.h"
20 #include "linear_solvers_define.h"
21 #if defined EIGEN_USE_MKL_ALL
23 #endif // defined EIGEN_USE_MKL_ALL
24 #include "eigen_sparse_lu_solver.h"
29 
30 namespace Kratos
31 {
32 
33 template<
34  class TSparseSpaceType = UblasSpace<double, CompressedMatrix, Vector>,
35  class TDenseSpaceType = UblasSpace<double, Matrix, Vector>,
36  class TPreconditionerType = Preconditioner<TSparseSpaceType, TDenseSpaceType>,
37  class TReordererType = Reorderer<TSparseSpaceType, TDenseSpaceType>>
39  : public IterativeSolver<TSparseSpaceType, TDenseSpaceType, TPreconditionerType, TReordererType>
40 {
41  Parameters mParam;
42 
43  public:
45 
47 
49 
51 
53 
55  Parameters param
56  ) : mParam(param)
57  {
58  Parameters default_params(R"(
59  {
60  "solver_type": "eigen_eigensystem",
61  "number_of_eigenvalues": 1,
62  "normalize_eigenvectors": false,
63  "use_mkl_if_available": true,
64  "max_iteration": 1000,
65  "tolerance": 1e-6,
66  "echo_level": 1
67  })");
68 
69  mParam.ValidateAndAssignDefaults(default_params);
70 
71  BaseType::SetTolerance(mParam["tolerance"].GetDouble());
72  BaseType::SetMaxIterationsNumber(mParam["max_iteration"].GetInt());
73  }
74 
75  ~EigensystemSolver() override {}
76 
86  void Solve(
87  SparseMatrixType& rK,
88  SparseMatrixType& rM,
89  VectorType& rEigenvalues,
90  DenseMatrixType& rEigenvectors) override
91  {
92  using scalar_t = double;
93  using vector_t = Kratos::EigenDynamicVector<scalar_t>;
94  using matrix_t = Kratos::EigenDynamicMatrix<scalar_t>;
95 
96  // --- get settings
97 
98  const int nroot = mParam["number_of_eigenvalues"].GetInt();
99  const int max_iteration = BaseType::GetMaxIterationsNumber();
100  const double tolerance = BaseType::GetTolerance();
101  const int echo_level = mParam["echo_level"].GetInt();
102 
103 
104  // --- wrap ublas matrices
105 
106  UblasWrapper<scalar_t> a_wrapper(rK);
107  UblasWrapper<scalar_t> b_wrapper(rM);
108 
109  const auto& a = a_wrapper.matrix();
110  const auto& b = b_wrapper.matrix();
111 
112 
113  // --- timer
114  const auto timer = BuiltinTimer();
115 
116  KRATOS_INFO_IF("EigensystemSolver:", echo_level > 0) << "Start" << std::endl;
117 
118  // --- calculation
119 
120  int nn = a.rows();
121  int nc = std::min(2 * nroot, nroot + 8);
122 
123  // projections
124  matrix_t ar(nc, nc);
125  matrix_t br(nc, nc);
126 
127  // storage for eigenvalues
128  vector_t prev_eigv = vector_t::Zero(nc);
129 
130  // storage for eigenvectors
131  matrix_t r = matrix_t::Zero(nn, nc);
132  for (int i = 0; i != nn; ++i) {
133  r(i, 0) = b.coeff(i, i);
134  }
135 
136  vector_t tmp(nn);
137 
138  // working vector
139  vector_t w(nn);
140  for (int i = 0; i != nn; ++i) {
141  w(i) = r(i, 0) / a.coeff(i, i);
142  }
143 
144  int nd = nn / nc;
145  int l = nn - nd;
146 
147  vector_t tt(nn);
148  int ij = 0;
149 
150  tt(0) = 0.0;
151 
152  for (int j = 1; j != nc; ++j) {
153  double rt = 0.0;
154 
155  for (int i = 0; i != l; ++i) {
156  if (w(i) >= rt) {
157  rt = w(i);
158  ij = i;
159  }
160  }
161 
162  for (int i = l - 1; i != nn; ++i) {
163  if (w(i) > rt) {
164  rt = w(i);
165  ij = i;
166  }
167  }
168 
169  tt(j) = ij;
170  w(ij) = 0.0;
171 
172  l -= nd;
173 
174  r(ij, j) = 1.0;
175  }
176 
178 
179  #if defined USE_EIGEN_MKL
180  if (mParam["use_mkl_if_available"].GetBool()) {
181  p_solver = Kratos::make_unique<DirectSolverWrapper<EigenPardisoLUSolver<double>>>();
182  } else {
183  p_solver = Kratos::make_unique<DirectSolverWrapper<EigenSparseLUSolver<double>>>();
184  }
185  #else // defined USE_EIGEN_MKL
186  p_solver = Kratos::make_unique<DirectSolverWrapper<EigenSparseLUSolver<double>>>();
187  #endif // defined USE_EIGEN_MKL
188 
189  p_solver->Compute(a);
190 
191  int iteration = 0;
192 
193  Eigen::GeneralizedSelfAdjointEigenSolver<matrix_t> eig;
194 
195  do {
196  iteration++;
197 
198  KRATOS_INFO_IF("EigensystemSolver:", echo_level > 1) << "Iteration " << iteration <<std::endl;
199 
200  for (int j = 0; j != nc; ++j) {
201  tmp = r.col(j);
202  p_solver->Solve(tmp, tt);
203 
204  for (int i = j; i != nc; ++i) {
205  ar(i, j) = r.col(i).dot(tt);
206  }
207 
208  r.col(j) = tt;
209  }
210 
211  for (int j = 0; j != nc; ++j) {
212  tt = b * r.col(j);
213 
214  for (int i = j; i != nc; ++i) {
215  br(i, j) = r.col(i).dot(tt);
216  }
217 
218  r.col(j) = tt;
219  }
220 
221  eig.compute(ar, br);
222 
223  if(eig.info() != Eigen::Success) {
224  KRATOS_WARNING("EigensystemSolver:") << "Eigen solution was not successful!" << std::endl;
225  break;
226  }
227 
228  r *= eig.eigenvectors();
229 
230  bool is_converged = true;
231  for (int i = 0; i != nc; i++) {
232  double eigv = eig.eigenvalues()(i);
233  double dif = eigv - prev_eigv(i);
234  double rtolv = std::abs(dif / eigv);
235 
236  if (rtolv > tolerance) {
237  is_converged = false;
238  KRATOS_WARNING_IF("EigensystemSolver:", echo_level > 1) << "Convergence not reached for eigenvalue #"<<i+1<<": " << rtolv <<"." << std::endl;
239  break;
240  }
241  }
242 
243  if (is_converged) {
244  KRATOS_INFO_IF("EigensystemSolver:", echo_level > 0) << "Convergence reached after " << iteration << " iterations within a relative tolerance: " << tolerance << std::endl;
245  break;
246  } else if (iteration >= max_iteration) {
247  KRATOS_INFO_IF("EigensystemSolver:", echo_level > 0) << "Convergence not reached in " << max_iteration << " iterations." << std::endl;
248  break;
249  }
250 
251  prev_eigv = eig.eigenvalues();
252  } while (true);
253 
254 
255  if (static_cast<int>(rEigenvalues.size()) != nroot) {
256  rEigenvalues.resize(nroot);
257  }
258  if (static_cast<int>(rEigenvectors.size1()) != nroot || static_cast<int>(rEigenvectors.size2()) != nn) {
259  rEigenvectors.resize(nroot, nn);
260  }
261 
262  Eigen::Map<vector_t> eigvals (rEigenvalues.data().begin(), rEigenvalues.size());
263  Eigen::Map<matrix_t> eigvecs (rEigenvectors.data().begin(), rEigenvectors.size1(), rEigenvectors.size2());
264 
265  eigvals = eig.eigenvalues().head(nroot);
266 
267  for (int i = 0; i != nroot; ++i) {
268  tmp = r.col(i);
269  p_solver->Solve(tmp, eigvecs.row(i));
270  eigvecs.row(i).normalize();
271  }
272 
273  // --- normalization
274  // Given generalized eigenvalue problem (A - eigenvalue * B) * eigenvector = 0,
275  // eigenvector is normalized such that eigenvector^T * B * eigenvector = 1
276  if(mParam["normalize_eigenvectors"].GetBool())
277  {
278  for (int i = 0; i != nroot; ++i)
279  {
280  const double tmp = eigvecs.row(i) * b * eigvecs.row(i).transpose();
281  const double factor = 1.0 / std::sqrt(tmp);
282  eigvecs.row(i) *= factor;
283  KRATOS_INFO_IF("EigensystemSolver:", echo_level > 0) << "Eigenvector " << i+1 << " is normalized - used factor: " << factor << std::endl;
284  }
285  }
286 
287  // --- output
288  if (echo_level > 0) {
289  Eigen::IOFormat fmt(Eigen::StreamPrecision, Eigen::DontAlignCols, ", ", ", ", "", "", "[ ", " ]");
290 
291  KRATOS_INFO("EigensystemSolver:") << "Completed in " << timer << std::endl
292  << " Eigenvalues = " << eigvals.transpose().format(fmt) << std::endl;
293  }
294  }
295 
299  void PrintInfo(std::ostream &rOStream) const override
300  {
301  rOStream << "EigensystemSolver";
302  }
303 
307  void PrintData(std::ostream &rOStream) const override
308  {
309  }
310 
311 private:
312 
313  struct DirectSolverWrapperBase
314  {
315  typedef Eigen::Map<const Kratos::EigenSparseMatrix<double>> MatrixMapType;
316  typedef Kratos::EigenDynamicVector<double> EigenVectorType;
317  typedef Eigen::Ref<const EigenVectorType> ConstVectorRefType;
318  typedef Eigen::Ref<EigenVectorType> VectorRefType;
319 
320  virtual ~DirectSolverWrapperBase() = default;
321  virtual void Compute(MatrixMapType a) = 0;
322  virtual void Solve(ConstVectorRefType b, VectorRefType x) = 0;
323  };
324 
325  template<class TSolver>
326  struct DirectSolverWrapper : DirectSolverWrapperBase
327  {
328  typedef DirectSolverWrapperBase BaseType;
329  typedef typename BaseType::MatrixMapType MatrixMapType;
330  typedef typename BaseType::VectorRefType VectorRefType;
331  typedef typename BaseType::ConstVectorRefType ConstVectorRefType;
332 
333  void Compute(MatrixMapType a) override {mSolver.Compute(a);}
334  void Solve(ConstVectorRefType b, VectorRefType x) override {mSolver.Solve(b, x);}
335  private:
336  TSolver mSolver;
337  };
338 
339 }; // class EigensystemSolver
340 
341 
345 template<class TSparseSpaceType, class TDenseSpaceType, class TReordererType>
346 inline std::istream& operator >>(
347  std::istream& rIStream,
348  EigensystemSolver<TSparseSpaceType,
349  TDenseSpaceType,
350  TReordererType>& rThis)
351 {
352  return rIStream;
353 }
354 
358 template<class TSparseSpaceType, class TDenseSpaceType, class TReordererType>
359 inline std::ostream& operator <<(
360  std::ostream& rOStream,
362 {
363  rThis.PrintInfo(rOStream);
364  rOStream << std::endl;
365  rThis.PrintData(rOStream);
366 
367  return rOStream;
368 }
369 
370 } // namespace Kratos
371 
372 #endif // defined(KRATOS_EIGENSYSTEM_SOLVER_H_INCLUDED)
Definition: builtin_timer.h:26
Definition: eigensystem_solver.h:40
void Solve(SparseMatrixType &rK, SparseMatrixType &rM, VectorType &rEigenvalues, DenseMatrixType &rEigenvectors) override
Definition: eigensystem_solver.h:86
TDenseSpaceType::MatrixType DenseMatrixType
Definition: eigensystem_solver.h:52
~EigensystemSolver() override
Definition: eigensystem_solver.h:75
TSparseSpaceType::VectorType VectorType
Definition: eigensystem_solver.h:50
EigensystemSolver(Parameters param)
Definition: eigensystem_solver.h:54
TSparseSpaceType::MatrixType SparseMatrixType
Definition: eigensystem_solver.h:48
void PrintInfo(std::ostream &rOStream) const override
Definition: eigensystem_solver.h:299
void PrintData(std::ostream &rOStream) const override
Definition: eigensystem_solver.h:307
IterativeSolver< TSparseSpaceType, TDenseSpaceType, TPreconditionerType, TReordererType > BaseType
Definition: eigensystem_solver.h:46
KRATOS_CLASS_POINTER_DEFINITION(EigensystemSolver)
Base class for all the iterative solvers in Kratos.
Definition: iterative_solver.h:68
void SetTolerance(double NewTolerance) override
This method allows to set the tolerance in the linear solver.
Definition: iterative_solver.h:305
virtual void SetMaxIterationsNumber(unsigned int NewMaxIterationsNumber)
Definition: iterative_solver.h:285
virtual IndexType GetMaxIterationsNumber()
Definition: iterative_solver.h:290
double GetTolerance() override
This method allows to get the tolerance in the linear solver.
Definition: iterative_solver.h:310
TSparseSpaceType::MatrixType SparseMatrixType
Definition: linear_solver.h:73
TDenseSpaceType::MatrixType DenseMatrixType
Definition: linear_solver.h:81
TSparseSpaceType::VectorType VectorType
Definition: linear_solver.h:77
This class provides to Kratos a data structure for I/O based on the standard of JSON.
Definition: kratos_parameters.h:59
Definition: ublas_wrapper.h:32
const Eigen::Map< const TEigenSparseMatrix > & matrix() const
Definition: ublas_wrapper.h:53
#define KRATOS_INFO(label)
Definition: logger.h:250
#define KRATOS_INFO_IF(label, conditional)
Definition: logger.h:251
#define KRATOS_WARNING_IF(label, conditional)
Definition: logger.h:266
#define KRATOS_WARNING(label)
Definition: logger.h:265
iteration
Definition: DEM_benchmarks.py:172
Vector VectorType
Definition: geometrical_transformation_utilities.h:56
Matrix MatrixType
Definition: geometrical_transformation_utilities.h:55
static double min(double a, double b)
Definition: GeometryFunctions.h:71
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
Eigen::Matrix< _Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > EigenDynamicMatrix
Definition: linear_solvers_define.h:32
std::unique_ptr< T > unique_ptr
Definition: smart_pointers.h:33
std::istream & operator>>(std::istream &rIStream, LinearMasterSlaveConstraint &rThis)
input stream function
TABLE_NUMBER_ANGULAR_VELOCITY TABLE_NUMBER_MOMENT I33 BEAM_INERTIA_ROT_UNIT_LENGHT_Y KRATOS_DEFINE_APPLICATION_VARIABLE(DEM_APPLICATION, double, BEAM_INERTIA_ROT_UNIT_LENGHT_Z) typedef std double
Definition: DEM_application_variables.h:182
std::ostream & operator<<(std::ostream &rOStream, const LinearMasterSlaveConstraint &rThis)
output stream function
Definition: linear_master_slave_constraint.h:432
Eigen::Matrix< _Scalar, Eigen::Dynamic, 1 > EigenDynamicVector
Definition: linear_solvers_define.h:33
w
Definition: generate_convection_diffusion_explicit_element.py:108
a
Definition: generate_stokes_twofluid_element.py:77
tuple tmp
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:98
b
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:31
int j
Definition: quadrature.py:648
echo_level
Definition: script.py:68
x
Definition: sensitivityMatrix.py:49
integer i
Definition: TensorModule.f:17
integer l
Definition: TensorModule.f:17
Definition: timer.py:1
float factor
for node in (self.combined_model_part).Nodes: pold = node.GetSolutionStepValue(PRESSURE,...
Definition: ulf_PGLASS.py:254