Dune Core Modules (unstable)

fmatrixev.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 #ifndef DUNE_FMATRIXEIGENVALUES_HH
6 #define DUNE_FMATRIXEIGENVALUES_HH
7 
12 #include <algorithm>
13 #include <iostream>
14 #include <cmath>
15 #include <cassert>
16 
18 #include <dune/common/fvector.hh>
19 #include <dune/common/fmatrix.hh>
20 #include <dune/common/math.hh>
21 
22 namespace Dune {
23 
29  namespace FMatrixHelp {
30 
31 #if HAVE_LAPACK
32  // defined in fmatrixev.cc
33  extern void eigenValuesLapackCall(
34  const char* jobz, const char* uplo, const long
35  int* n, double* a, const long int* lda, double* w,
36  double* work, const long int* lwork, long int* info);
37 
38  extern void eigenValuesNonsymLapackCall(
39  const char* jobvl, const char* jobvr, const long
40  int* n, double* a, const long int* lda, double* wr, double* wi, double* vl,
41  const long int* ldvl, double* vr, const long int* ldvr, double* work,
42  const long int* lwork, long int* info);
43 
44  extern void eigenValuesLapackCall(
45  const char* jobz, const char* uplo, const long
46  int* n, float* a, const long int* lda, float* w,
47  float* work, const long int* lwork, long int* info);
48 
49  extern void eigenValuesNonsymLapackCall(
50  const char* jobvl, const char* jobvr, const long
51  int* n, float* a, const long int* lda, float* wr, float* wi, float* vl,
52  const long int* ldvl, float* vr, const long int* ldvr, float* work,
53  const long int* lwork, long int* info);
54 
55 #endif
56 
57  namespace Impl {
58  //internal tag to activate/disable code for eigenvector calculation at compile time
59  enum Jobs { OnlyEigenvalues=0, EigenvaluesEigenvectors=1 };
60 
61  //internal dummy used if only eigenvalues are to be calculated
62  template<typename K, int dim>
63  using EVDummy = FieldMatrix<K, dim, dim>;
64 
65  //compute the cross-product of two vectors
66  template<typename K>
67  inline FieldVector<K,3> crossProduct(const FieldVector<K,3>& vec0, const FieldVector<K,3>& vec1) {
68  return {vec0[1]*vec1[2] - vec0[2]*vec1[1], vec0[2]*vec1[0] - vec0[0]*vec1[2], vec0[0]*vec1[1] - vec0[1]*vec1[0]};
69  }
70 
71  template <typename K>
72  static void eigenValues2dImpl(const FieldMatrix<K, 2, 2>& matrix,
73  FieldVector<K, 2>& eigenvalues)
74  {
75  using std::sqrt;
76  const K p = 0.5 * (matrix[0][0] + matrix [1][1]);
77  const K p2 = p - matrix[1][1];
78  K q = p2 * p2 + matrix[1][0] * matrix[0][1];
79  if( q < 0 && q > -1e-14 ) q = 0;
80  if (q < 0)
81  {
82  std::cout << matrix << std::endl;
83  // Complex eigenvalues are either caused by non-symmetric matrices or by round-off errors
84  DUNE_THROW(MathError, "Complex eigenvalue detected (which this implementation cannot handle).");
85  }
86 
87  // get square root
88  q = sqrt(q);
89 
90  // store eigenvalues in ascending order
91  eigenvalues[0] = p - q;
92  eigenvalues[1] = p + q;
93  }
94 
95  /*
96  This implementation was adapted from the pseudo-code (Python?) implementation found on
97  http://en.wikipedia.org/wiki/Eigenvalue_algorithm (retrieved late August 2014).
98  Wikipedia claims to have taken it from
99  Smith, Oliver K. (April 1961), Eigenvalues of a symmetric 3 × 3 matrix.,
100  Communications of the ACM 4 (4): 168, doi:10.1145/355578.366316
101  */
102  template <typename K>
103  static K eigenValues3dImpl(const FieldMatrix<K, 3, 3>& matrix,
104  FieldVector<K, 3>& eigenvalues)
105  {
106  using std::sqrt;
107  using std::acos;
108  using real_type = typename FieldTraits<K>::real_type;
109  const K pi = MathematicalConstants<K>::pi();
110  K p1 = matrix[0][1]*matrix[0][1] + matrix[0][2]*matrix[0][2] + matrix[1][2]*matrix[1][2];
111 
112  if (p1 <= std::numeric_limits<K>::epsilon()) {
113  // A is diagonal.
114  eigenvalues[0] = matrix[0][0];
115  eigenvalues[1] = matrix[1][1];
116  eigenvalues[2] = matrix[2][2];
117  std::sort(eigenvalues.begin(), eigenvalues.end());
118 
119  return 0.0;
120  }
121  else
122  {
123  // q = trace(A)/3
124  K q = 0;
125  for (int i=0; i<3; i++)
126  q += matrix[i][i] / 3.0;
127 
128  K p2 = (matrix[0][0] - q)*(matrix[0][0] - q) + (matrix[1][1] - q)*(matrix[1][1] - q) + (matrix[2][2] - q)*(matrix[2][2] - q) + 2.0 * p1;
129  K p = sqrt(p2 / 6);
130  // B = (1 / p) * (A - q * I); // I is the identity matrix
131  FieldMatrix<K,3,3> B;
132  for (int i=0; i<3; i++)
133  for (int j=0; j<3; j++)
134  B[i][j] = (real_type(1.0)/p) * (matrix[i][j] - q*(i==j));
135 
136  K r = B.determinant() / 2.0;
137 
138  /*In exact arithmetic for a symmetric matrix -1 <= r <= 1
139  but computation error can leave it slightly outside this range.
140  acos(z) function requires |z| <= 1, but will fail silently
141  and return NaN if the input is larger than 1 in magnitude.
142  Thus r is clamped to [-1,1].*/
143  using std::clamp;
144  r = clamp<K>(r, -1.0, 1.0);
145  K phi = acos(r) / 3.0;
146 
147  // the eigenvalues satisfy eig[2] <= eig[1] <= eig[0]
148  eigenvalues[2] = q + 2 * p * cos(phi);
149  eigenvalues[0] = q + 2 * p * cos(phi + (2*pi/3));
150  eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2]; // since trace(matrix) = eig1 + eig2 + eig3
151 
152  return r;
153  }
154  }
155 
156  //see https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf
157  //Robustly compute a right-handed orthonormal set {u, v, evec0}.
158  template<typename K>
159  void orthoComp(const FieldVector<K,3>& evec0, FieldVector<K,3>& u, FieldVector<K,3>& v) {
160  using std::abs;
161  if(abs(evec0[0]) > abs(evec0[1])) {
162  //The component of maximum absolute value is either evec0[0] or evec0[2].
163  FieldVector<K,2> temp = {evec0[0], evec0[2]};
164  auto L = 1.0 / temp.two_norm();
165  u = L * FieldVector<K,3>({-evec0[2], 0.0, evec0[0]});
166  }
167  else {
168  //The component of maximum absolute value is either evec0[1] or evec0[2].
169  FieldVector<K,2> temp = {evec0[1], evec0[2]};
170  auto L = 1.0 / temp.two_norm();
171  u = L * FieldVector<K,3>({0.0, evec0[2], -evec0[1]});
172  }
173  v = crossProduct(evec0, u);
174  }
175 
176  //see https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf
177  template<typename K>
178  void eig0(const FieldMatrix<K,3,3>& matrix, K eval0, FieldVector<K,3>& evec0) {
179  /* Compute a unit-length eigenvector for eigenvalue[i0]. The
180  matrix is rank 2, so two of the rows are linearly independent.
181  For a robust computation of the eigenvector, select the two
182  rows whose cross product has largest length of all pairs of
183  rows. */
184  using Vector = FieldVector<K,3>;
185  Vector row0 = {matrix[0][0]-eval0, matrix[0][1], matrix[0][2]};
186  Vector row1 = {matrix[1][0], matrix[1][1]-eval0, matrix[1][2]};
187  Vector row2 = {matrix[2][0], matrix[2][1], matrix[2][2]-eval0};
188 
189  Vector r0xr1 = crossProduct(row0, row1);
190  Vector r0xr2 = crossProduct(row0, row2);
191  Vector r1xr2 = crossProduct(row1, row2);
192  auto d0 = r0xr1.two_norm();
193  auto d1 = r0xr2.two_norm();
194  auto d2 = r1xr2.two_norm();
195 
196  auto dmax = d0 ;
197  int imax = 0;
198  if(d1>dmax) {
199  dmax = d1;
200  imax = 1;
201  }
202  if(d2>dmax)
203  imax = 2;
204 
205  if(imax == 0)
206  evec0 = r0xr1 / d0;
207  else if(imax == 1)
208  evec0 = r0xr2 / d1;
209  else
210  evec0 = r1xr2 / d2;
211  }
212 
213  //see https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf
214  template<typename K>
215  void eig1(const FieldMatrix<K,3,3>& matrix, const FieldVector<K,3>& evec0, FieldVector<K,3>& evec1, K eval1) {
216  using Vector = FieldVector<K,3>;
217 
218  //Robustly compute a right-handed orthonormal set {u, v, evec0}.
219  Vector u,v;
220  orthoComp(evec0, u, v);
221 
222  /* Let e be eval1 and let E be a corresponding eigenvector which
223  is a solution to the linear system (A - e*I)*E = 0. The matrix
224  (A - e*I) is 3x3, not invertible (so infinitely many
225  solutions), and has rank 2 when eval1 and eval are different.
226  It has rank 1 when eval1 and eval2 are equal. Numerically, it
227  is difficult to compute robustly the rank of a matrix. Instead,
228  the 3x3 linear system is reduced to a 2x2 system as follows.
229  Define the 3x2 matrix J = [u,v] whose columns are the u and v
230  computed previously. Define the 2x1 vector X = J*E. The 2x2
231  system is 0 = M * X = (J^T * (A - e*I) * J) * X where J^T is
232  the transpose of J and M = J^T * (A - e*I) * J is a 2x2 matrix.
233  The system may be written as
234  +- -++- -+ +- -+
235  | U^T*A*U - e U^T*A*V || x0 | = e * | x0 |
236  | V^T*A*U V^T*A*V - e || x1 | | x1 |
237  +- -++ -+ +- -+
238  where X has row entries x0 and x1. */
239 
240  Vector Au, Av;
241  matrix.mv(u, Au);
242  matrix.mv(v, Av);
243 
244  auto m00 = u.dot(Au) - eval1;
245  auto m01 = u.dot(Av);
246  auto m11 = v.dot(Av) - eval1;
247 
248  /* For robustness, choose the largest-length row of M to compute
249  the eigenvector. The 2-tuple of coefficients of U and V in the
250  assignments to eigenvector[1] lies on a circle, and U and V are
251  unit length and perpendicular, so eigenvector[1] is unit length
252  (within numerical tolerance). */
253  using std::abs, std::sqrt, std::max;
254  auto absM00 = abs(m00);
255  auto absM01 = abs(m01);
256  auto absM11 = abs(m11);
257  if(absM00 >= absM11) {
258  auto maxAbsComp = max(absM00, absM01);
259  if(maxAbsComp > 0.0) {
260  if(absM00 >= absM01) {
261  m01 /= m00;
262  m00 = 1.0 / sqrt(1.0 + m01*m01);
263  m01 *= m00;
264  }
265  else {
266  m00 /= m01;
267  m01 = 1.0 / sqrt(1.0 + m00*m00);
268  m00 *= m01;
269  }
270  evec1 = m01*u - m00*v;
271  }
272  else
273  evec1 = u;
274  }
275  else {
276  auto maxAbsComp = max(absM11, absM01);
277  if(maxAbsComp > 0.0) {
278  if(absM11 >= absM01) {
279  m01 /= m11;
280  m11 = 1.0 / sqrt(1.0 + m01*m01);
281  m01 *= m11;
282  }
283  else {
284  m11 /= m01;
285  m01 = 1.0 / sqrt(1.0 + m11*m11);
286  m11 *= m01;
287  }
288  evec1 = m11*u - m01*v;
289  }
290  else
291  evec1 = u;
292  }
293  }
294 
295  // 1d specialization
296  template<Jobs Tag, typename K>
297  static void eigenValuesVectorsImpl(const FieldMatrix<K, 1, 1>& matrix,
298  FieldVector<K, 1>& eigenValues,
299  FieldMatrix<K, 1, 1>& eigenVectors)
300  {
301  eigenValues[0] = matrix[0][0];
302  if constexpr(Tag==EigenvaluesEigenvectors)
303  eigenVectors[0] = {1.0};
304  }
305 
306 
307  // 2d specialization
308  template <Jobs Tag, typename K>
309  static void eigenValuesVectorsImpl(const FieldMatrix<K, 2, 2>& matrix,
310  FieldVector<K, 2>& eigenValues,
311  FieldMatrix<K, 2, 2>& eigenVectors)
312  {
313  // Compute eigen values
314  Impl::eigenValues2dImpl(matrix, eigenValues);
315 
316  // Compute eigenvectors by exploiting the Cayley–Hamilton theorem.
317  // If λ_1, λ_2 are the eigenvalues, then (A - λ_1I )(A - λ_2I ) = (A - λ_2I )(A - λ_1I ) = 0,
318  // so the columns of (A - λ_2I ) are annihilated by (A - λ_1I ) and vice versa.
319  // Assuming neither matrix is zero, the columns of each must include eigenvectors
320  // for the other eigenvalue. (If either matrix is zero, then A is a multiple of the
321  // identity and any non-zero vector is an eigenvector.)
322  // From: https://en.wikipedia.org/wiki/Eigenvalue_algorithm#2x2_matrices
323  if constexpr(Tag==EigenvaluesEigenvectors) {
324 
325  // Special casing for multiples of the identity
326  FieldMatrix<K,2,2> temp = matrix;
327  temp[0][0] -= eigenValues[0];
328  temp[1][1] -= eigenValues[0];
329  if(temp.infinity_norm() <= 1e-14) {
330  eigenVectors[0] = {1.0, 0.0};
331  eigenVectors[1] = {0.0, 1.0};
332  }
333  else {
334  // The columns of A - λ_2I are eigenvectors for λ_1, or zero.
335  // Take the column with the larger norm to avoid zero columns.
336  FieldVector<K,2> ev0 = {matrix[0][0]-eigenValues[1], matrix[1][0]};
337  FieldVector<K,2> ev1 = {matrix[0][1], matrix[1][1]-eigenValues[1]};
338  eigenVectors[0] = (ev0.two_norm2() >= ev1.two_norm2()) ? ev0/ev0.two_norm() : ev1/ev1.two_norm();
339 
340  // The columns of A - λ_1I are eigenvectors for λ_2, or zero.
341  // Take the column with the larger norm to avoid zero columns.
342  ev0 = {matrix[0][0]-eigenValues[0], matrix[1][0]};
343  ev1 = {matrix[0][1], matrix[1][1]-eigenValues[0]};
344  eigenVectors[1] = (ev0.two_norm2() >= ev1.two_norm2()) ? ev0/ev0.two_norm() : ev1/ev1.two_norm();
345  }
346  }
347  }
348 
349  // 3d specialization
350  template <Jobs Tag, typename K>
351  static void eigenValuesVectorsImpl(const FieldMatrix<K, 3, 3>& matrix,
352  FieldVector<K, 3>& eigenValues,
353  FieldMatrix<K, 3, 3>& eigenVectors)
354  {
355  using Vector = FieldVector<K,3>;
356  using Matrix = FieldMatrix<K,3,3>;
357 
358  //compute eigenvalues
359  /* Precondition the matrix by factoring out the maximum absolute
360  value of the components. This guards against floating-point
361  overflow when computing the eigenvalues.*/
362  using std::isnormal;
363  K maxAbsElement = (isnormal(matrix.infinity_norm())) ? matrix.infinity_norm() : K(1.0);
364  Matrix scaledMatrix = matrix / maxAbsElement;
365  K r = Impl::eigenValues3dImpl(scaledMatrix, eigenValues);
366 
367  if constexpr(Tag==EigenvaluesEigenvectors) {
368  K offDiagNorm = Vector{scaledMatrix[0][1],scaledMatrix[0][2],scaledMatrix[1][2]}.two_norm2();
369  if (offDiagNorm <= std::numeric_limits<K>::epsilon())
370  {
371  eigenValues = {scaledMatrix[0][0], scaledMatrix[1][1], scaledMatrix[2][2]};
372  eigenVectors = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
373 
374  // Use bubble sort to jointly sort eigenvalues and eigenvectors
375  // such that eigenvalues are ascending
376  if (eigenValues[0] > eigenValues[1])
377  {
378  std::swap(eigenValues[0], eigenValues[1]);
379  std::swap(eigenVectors[0], eigenVectors[1]);
380  }
381  if (eigenValues[1] > eigenValues[2])
382  {
383  std::swap(eigenValues[1], eigenValues[2]);
384  std::swap(eigenVectors[1], eigenVectors[2]);
385  }
386  if (eigenValues[0] > eigenValues[1])
387  {
388  std::swap(eigenValues[0], eigenValues[1]);
389  std::swap(eigenVectors[0], eigenVectors[1]);
390  }
391  }
392  else {
393  /*Compute the eigenvectors so that the set
394  [evec[0], evec[1], evec[2]] is right handed and
395  orthonormal. */
396 
397  Matrix evec(0.0);
398  Vector eval(eigenValues);
399  if(r >= 0) {
400  Impl::eig0(scaledMatrix, eval[2], evec[2]);
401  Impl::eig1(scaledMatrix, evec[2], evec[1], eval[1]);
402  evec[0] = Impl::crossProduct(evec[1], evec[2]);
403  }
404  else {
405  Impl::eig0(scaledMatrix, eval[0], evec[0]);
406  Impl::eig1(scaledMatrix, evec[0], evec[1], eval[1]);
407  evec[2] = Impl::crossProduct(evec[0], evec[1]);
408  }
409  //sort eval/evec-pairs in ascending order
410  using EVPair = std::pair<K, Vector>;
411  std::vector<EVPair> pairs;
412  for(std::size_t i=0; i<=2; ++i)
413  pairs.push_back(EVPair(eval[i], evec[i]));
414  auto comp = [](EVPair x, EVPair y){ return x.first < y.first; };
415  std::sort(pairs.begin(), pairs.end(), comp);
416  for(std::size_t i=0; i<=2; ++i){
417  eigenValues[i] = pairs[i].first;
418  eigenVectors[i] = pairs[i].second;
419  }
420  }
421  }
422  //The preconditioning scaled the matrix, which scales the eigenvalues. Revert the scaling.
423  eigenValues *= maxAbsElement;
424  }
425 
426  // forwarding to LAPACK with corresponding tag
427  template <Jobs Tag, int dim, typename K>
428  static void eigenValuesVectorsLapackImpl(const FieldMatrix<K, dim, dim>& matrix,
429  FieldVector<K, dim>& eigenValues,
430  FieldMatrix<K, dim, dim>& eigenVectors)
431  {
432  {
433 #if HAVE_LAPACK
434  /*Lapack uses a proprietary tag to determine whether both eigenvalues and
435  -vectors ('v') or only eigenvalues ('n') should be calculated */
436  const char jobz = "nv"[Tag];
437 
438  const long int N = dim ;
439  const char uplo = 'u'; // use upper triangular matrix
440 
441  // length of matrix vector, LWORK >= max(1,3*N-1)
442  const long int lwork = 3*N -1 ;
443 
444  constexpr bool isKLapackType = std::is_same_v<K,double> || std::is_same_v<K,float>;
445  using LapackNumType = std::conditional_t<isKLapackType, K, double>;
446 
447  // matrix to put into dsyev
448  LapackNumType matrixVector[dim * dim];
449 
450  // copy matrix
451  int row = 0;
452  for(int i=0; i<dim; ++i)
453  {
454  for(int j=0; j<dim; ++j, ++row)
455  {
456  matrixVector[ row ] = matrix[ i ][ j ];
457  }
458  }
459 
460  // working memory
461  LapackNumType workSpace[lwork];
462 
463  // return value information
464  long int info = 0;
465  LapackNumType* ev;
466  if constexpr (isKLapackType){
467  ev = &eigenValues[0];
468  }else{
469  ev = new LapackNumType[dim];
470  }
471 
472  // call LAPACK routine (see fmatrixev.cc)
473  eigenValuesLapackCall(&jobz, &uplo, &N, &matrixVector[0], &N,
474  ev, &workSpace[0], &lwork, &info);
475 
476  if constexpr (!isKLapackType){
477  for(size_t i=0;i<dim;++i)
478  eigenValues[i] = ev[i];
479  delete[] ev;
480  }
481 
482  // restore eigenvectors matrix
483  if (Tag==Jobs::EigenvaluesEigenvectors){
484  row = 0;
485  for(int i=0; i<dim; ++i)
486  {
487  for(int j=0; j<dim; ++j, ++row)
488  {
489  eigenVectors[ i ][ j ] = matrixVector[ row ];
490  }
491  }
492  }
493 
494  if( info != 0 )
495  {
496  std::cerr << "For matrix " << matrix << " eigenvalue calculation failed! " << std::endl;
497  DUNE_THROW(InvalidStateException,"eigenValues: Eigenvalue calculation failed!");
498  }
499 #else
500  DUNE_THROW(NotImplemented,"LAPACK not found!");
501 #endif
502  }
503  }
504 
505  // generic specialization
506  template <Jobs Tag, int dim, typename K>
507  static void eigenValuesVectorsImpl(const FieldMatrix<K, dim, dim>& matrix,
508  FieldVector<K, dim>& eigenValues,
509  FieldMatrix<K, dim, dim>& eigenVectors)
510  {
511  eigenValuesVectorsLapackImpl<Tag>(matrix,eigenValues,eigenVectors);
512  }
513  } //namespace Impl
514 
522  template <int dim, typename K>
523  static void eigenValues(const FieldMatrix<K, dim, dim>& matrix,
524  FieldVector<K ,dim>& eigenValues)
525  {
526  Impl::EVDummy<K,dim> dummy;
527  Impl::eigenValuesVectorsImpl<Impl::Jobs::OnlyEigenvalues>(matrix, eigenValues, dummy);
528  }
529 
538  template <int dim, typename K>
539  static void eigenValuesVectors(const FieldMatrix<K, dim, dim>& matrix,
540  FieldVector<K ,dim>& eigenValues,
541  FieldMatrix<K, dim, dim>& eigenVectors)
542  {
543  Impl::eigenValuesVectorsImpl<Impl::Jobs::EigenvaluesEigenvectors>(matrix, eigenValues, eigenVectors);
544  }
545 
553  template <int dim, typename K>
554  static void eigenValuesLapack(const FieldMatrix<K, dim, dim>& matrix,
555  FieldVector<K, dim>& eigenValues)
556  {
557  Impl::EVDummy<K,dim> dummy;
558  Impl::eigenValuesVectorsLapackImpl<Impl::Jobs::EigenvaluesEigenvectors>(matrix, eigenValues, dummy);
559  }
560 
569  template <int dim, typename K>
571  FieldVector<K, dim>& eigenValues,
572  FieldMatrix<K, dim, dim>& eigenVectors)
573  {
574  Impl::eigenValuesVectorsLapackImpl<Impl::Jobs::EigenvaluesEigenvectors>(matrix, eigenValues, eigenVectors);
575  }
576 
584  template <int dim, typename K, class C>
585  static void eigenValuesNonSym(const FieldMatrix<K, dim, dim>& matrix,
586  FieldVector<C, dim>& eigenValues)
587  {
588 #if HAVE_LAPACK
589  {
590  const long int N = dim ;
591  const char jobvl = 'n';
592  const char jobvr = 'n';
593 
594  constexpr bool isKLapackType = std::is_same_v<K,double> || std::is_same_v<K,float>;
595  using LapackNumType = std::conditional_t<isKLapackType, K, double>;
596 
597  // matrix to put into dgeev
598  LapackNumType matrixVector[dim * dim];
599 
600  // copy matrix
601  int row = 0;
602  for(int i=0; i<dim; ++i)
603  {
604  for(int j=0; j<dim; ++j, ++row)
605  {
606  matrixVector[ row ] = matrix[ i ][ j ];
607  }
608  }
609 
610  // working memory
611  LapackNumType eigenR[dim];
612  LapackNumType eigenI[dim];
613  LapackNumType work[3*dim];
614 
615  // return value information
616  long int info = 0;
617  const long int lwork = 3*dim;
618 
619  // call LAPACK routine (see fmatrixev_ext.cc)
620  eigenValuesNonsymLapackCall(&jobvl, &jobvr, &N, &matrixVector[0], &N,
621  &eigenR[0], &eigenI[0], nullptr, &N, nullptr, &N, &work[0],
622  &lwork, &info);
623 
624  if( info != 0 )
625  {
626  std::cerr << "For matrix " << matrix << " eigenvalue calculation failed! " << std::endl;
627  DUNE_THROW(InvalidStateException,"eigenValues: Eigenvalue calculation failed!");
628  }
629  for (int i=0; i<N; ++i) {
630  eigenValues[i].real = eigenR[i];
631  eigenValues[i].imag = eigenI[i];
632  }
633  }
634 #else
635  DUNE_THROW(NotImplemented,"LAPACK not found!");
636 #endif
637  }
638  } // end namespace FMatrixHelp
639 
642 } // end namespace Dune
643 #endif
A dense n x m matrix.
Definition: fmatrix.hh:117
vector space out of a tensor product of fields.
Definition: fvector.hh:95
Default exception if a function was called while the object is not in a valid state for that function...
Definition: exceptions.hh:281
Default exception for dummy implementations.
Definition: exceptions.hh:263
A few common exception classes.
Implements a matrix constructed from a given type representing a field and compile-time given number ...
static void eigenValuesNonSym(const FieldMatrix< K, dim, dim > &matrix, FieldVector< C, dim > &eigenValues)
calculates the eigenvalues of a non-symmetric field matrix
Definition: fmatrixev.hh:585
static void eigenValues(const FieldMatrix< K, dim, dim > &matrix, FieldVector< K, dim > &eigenValues)
calculates the eigenvalues of a symmetric field matrix
Definition: fmatrixev.hh:523
static void eigenValuesLapack(const FieldMatrix< K, dim, dim > &matrix, FieldVector< K, dim > &eigenValues)
calculates the eigenvalues of a symmetric field matrix
Definition: fmatrixev.hh:554
static void eigenValuesVectors(const FieldMatrix< K, dim, dim > &matrix, FieldVector< K, dim > &eigenValues, FieldMatrix< K, dim, dim > &eigenVectors)
calculates the eigenvalues and eigenvectors of a symmetric field matrix
Definition: fmatrixev.hh:539
static void eigenValuesVectorsLapack(const FieldMatrix< K, dim, dim > &matrix, FieldVector< K, dim > &eigenValues, FieldMatrix< K, dim, dim > &eigenVectors)
calculates the eigenvalues and -vectors of a symmetric field matrix
Definition: fmatrixev.hh:570
Implements a vector constructed from a given type representing a field and a compile-time given size.
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:484
Some useful basic math stuff.
Dune namespace.
Definition: alignedallocator.hh:13
static const Field pi()
Archimedes' constant.
Definition: math.hh:48
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 3, 22:32, 2024)