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