From 220de22f7f98b385c48373adcfc3c8c74c14964c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Robert=20Kl=C3=B6fkorn?= <robertk@dune-project.org>
Date: Mon, 11 May 2009 09:20:17 +0000
Subject: [PATCH] eigen value calculation for a field matrix (using LAPACK for
 dim > 2)

[[Imported from SVN: r5516]]
---
 common/Makefile.am  |   2 +-
 common/fmatrix.hh   |   1 +
 common/fmatrixev.hh | 176 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 178 insertions(+), 1 deletion(-)
 create mode 100644 common/fmatrixev.hh

diff --git a/common/Makefile.am b/common/Makefile.am
index 660f33d8e..ff815efeb 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -12,7 +12,7 @@ AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/..
 commonincludedir = $(includedir)/dune/common
 commoninclude_HEADERS = alignment.hh \
   arraylist.hh bitsetvector.hh debugstream.hh deprecated.hh \
-  enumset.hh exceptions.hh fixedarray.hh fmatrix.hh \
+  enumset.hh exceptions.hh fixedarray.hh fmatrix.hh fmatrixev.hh \
   fvector.hh genericiterator.hh \
   helpertemplates.hh iteratorfacades.hh \
   misc.hh poolallocator.hh finitestack.hh \
diff --git a/common/fmatrix.hh b/common/fmatrix.hh
index fe1a2c735..708e8860b 100644
--- a/common/fmatrix.hh
+++ b/common/fmatrix.hh
@@ -1441,4 +1441,5 @@ namespace Dune {
 
 } // end namespace
 
+#include "fmatrixev.hh"
 #endif
diff --git a/common/fmatrixev.hh b/common/fmatrixev.hh
new file mode 100644
index 000000000..09093baa7
--- /dev/null
+++ b/common/fmatrixev.hh
@@ -0,0 +1,176 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifndef DUNE_FMATRIXEIGENVALUES_HH
+#define DUNE_FMATRIXEIGENVALUES_HH
+
+#include <iostream>
+#include <cmath>
+#include <cassert>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
+#if HAVE_LAPACK
+// dsyev declaration (in liblapack)
+extern "C" {
+
+  /*
+   *
+   **  purpose
+   **  =======
+   **
+   **  xsyev computes all eigenvalues and, optionally, eigenvectors of a
+   **  BASE DATA TYPE symmetric matrix a.
+   **
+   **  arguments
+   **  =========
+   **
+   **  jobz    (input) char
+   **          = 'n':  compute eigenvalues only;
+   **          = 'v':  compute eigenvalues and eigenvectors.
+   **
+   **  uplo    (input) char
+   **          = 'u':  upper triangle of a is stored;
+   **          = 'l':  lower triangle of a is stored.
+   **
+   **  n       (input) long int
+   **          the order of the matrix a.  n >= 0.
+   **
+   **  a       (input/output) BASE DATA TYPE array, dimension (lda, n)
+   **          on entry, the symmetric matrix a.  if uplo = 'u', the
+   **          leading n-by-n upper triangular part of a contains the
+   **          upper triangular part of the matrix a.  if uplo = 'l',
+   **          the leading n-by-n lower triangular part of a contains
+   **          the lower triangular part of the matrix a.
+   **          on exit, if jobz = 'v', then if info = 0, a contains the
+   **          orthonormal eigenvectors of the matrix a.
+   **          if jobz = 'n', then on exit the lower triangle (if uplo='l')
+   **          or the upper triangle (if uplo='u') of a, including the
+   **          diagonal, is destroyed.
+   **
+   **  lda     (input) long int
+   **          the leading dimension of the array a.  lda >= max(1,n).
+   **
+   **  w       (output) BASE DATA TYPE array, dimension (n)
+   **          if info = 0, the eigenvalues in ascending order.
+   **
+   **
+   **
+   **  info    (output) long int
+   **          = 0:  successful exit
+   **          < 0:  if info = -i, the i-th argument had an illegal value
+   **          > 0:  if info = i, the algorithm failed to converge; i
+   **                off-diagonal elements of an intermediate tridiagonal
+   **                form did not converge to zero.
+   **
+   **/
+  extern void dsyev_(const char* jobz, const char* uplo, const long
+                     int* n, double* a, const long int* lda, double* w,
+                     double* work, const long int* lwork, long int* info);
+} // end extern C
+#endif
+
+namespace Dune {
+
+  namespace FMatrixHelp {
+
+    /** \brief calculates the eigen values of a field matrix
+        \param[in]  matrix matrix eigen values are calculated for
+        \param[out] eigenvalues FieldVector that contains eigen values in
+                    ascending order
+     */
+    template <typename K>
+    static void eigenValues(const FieldMatrix<K, 1, 1>& matrix,
+                            FieldVector<K, 1>& eigenvalues)
+    {
+      eigenvalues[0] = matrix[0][0];
+    }
+
+    /** \brief calculates the eigen values of a field matrix
+        \param[in]  matrix matrix eigen values are calculated for
+        \param[out] eigenvalues FieldVector that contains eigen values in
+                    ascending order
+     */
+    template <typename K>
+    static void eigenValues(const FieldMatrix<K, 2, 2>& matrix,
+                            FieldVector<K, 2>& eigenvalues)
+    {
+      const K detM = matrix[0][0] * matrix[1][1] - matrix[1][0] * matrix[0][1];
+      const K p = 0.5 * (matrix[0][0] + matrix [1][1]);
+      K q = p * p - detM;
+      if( q < 0 && q > -1e-14 ) q = 0;
+      if (p < 0 || q < 0)
+      {
+        std::cout << p << " p | q " << q << "\n";
+        std::cout << matrix << std::endl;
+        std::cout << "something went wrong in Eigenvalues for matrix!" << std::endl;
+        assert(false);
+        abort();
+      }
+
+      // get square root
+      q = std :: sqrt(q);
+
+      // store eigenvalues in ascending order
+      eigenvalues[0] = p - q;
+      eigenvalues[1] = p + q;
+    }
+
+    /** \brief calculates the eigen values of a field matrix
+        \param[in]  matrix matrix eigen values are calculated for
+        \param[out] eigenvalues FieldVector that contains eigen values in
+                    ascending order
+
+        \note LAPACK::dsyev is used to calculate the eigen values
+     */
+    template <int dim, typename K>
+    static void eigenValues(const FieldMatrix<K, dim, dim>& matrix,
+                            FieldVector<K, dim>& eigenvalues)
+    {
+#if HAVE_LAPACK
+      {
+        const long int N = dim ;
+        const char jobz = 'n'; // only calculate eigen values
+        const char uplo = 'u'; // use upper triangular matrix
+
+        // length of matrix vector
+        const long int w = N * N ;
+
+        // matrix to put into dsyev
+        double matrixVector[dim * dim];
+
+        // copy matrix
+        int row = 0;
+        for(int i=0; i<dim; ++i)
+        {
+          for(int j=0; j<dim; ++j, ++row)
+          {
+            matrixVector[ row ] = matrix[ i ][ j ];
+          }
+        }
+
+        // working memory
+        double workSpace[dim * dim];
+
+        // return value information
+        long int info = 0;
+
+        // call LAPACK dsyev
+        dsyev_(&jobz, &uplo, &N, &matrixVector[0], &N,
+               &eigenvalues[0], &workSpace[0], &w, &info);
+
+        if( info != 0 )
+        {
+          std::cerr << "For matrix " << matrix << " eigen value calculation falied! " << std::endl;
+          DUNE_THROW(InvalidStateException,"eigenValues: Eigenvalue calculation failed!");
+        }
+      }
+#else
+      DUNE_THROW(NotImplemented,"LAPACK is not availble, therefore no eigen value calculation");
+#endif
+    }
+
+  } // end namespace FMatrixHelp
+} // end namespace Dune
+#endif
-- 
GitLab