diff --git a/COPYING b/COPYING index b076a2ed1c7e9e86673290b6b85921cf64073621..07a2ee7721774b6751250061c1980ec9d615a09a 100644 --- a/COPYING +++ b/COPYING @@ -13,6 +13,7 @@ Copyright holders: 2010--2012 Christoph Grüninger 2006 Bernhard Haasdonk 2012 Olaf Ippisch +2012 Arne Morten Kvarving 2009 Leonard Kern 2005--2007 Sreejith Pulloor Kuttanikkad 2003--2012 Robert Klöfkorn diff --git a/dune/common/Makefile.am b/dune/common/Makefile.am index 4cd44bc9916e804d3c637be4fee6314e4695a39d..3a71534cec123dd9b7d0edbd602c4eadf0298e85 100644 --- a/dune/common/Makefile.am +++ b/dune/common/Makefile.am @@ -8,6 +8,7 @@ noinst_LTLIBRARIES = libcommon.la libcommon_la_SOURCES = \ debugallocator.cc \ fmatrixev.cc \ + dynmatrixev.cc \ ios_state.cc \ parametertree.cc \ parametertreeparser.cc \ diff --git a/dune/common/dynmatrixev.cc b/dune/common/dynmatrixev.cc new file mode 100644 index 0000000000000000000000000000000000000000..1a6eed61ba765cf9548066b455dafbcc402dd203 --- /dev/null +++ b/dune/common/dynmatrixev.cc @@ -0,0 +1,154 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_FMATRIXEIGENVALUES_EXT_CC +#define DUNE_FMATRIXEIGENVALUES_EXT_CC + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <iostream> +#include <cmath> +#include <cassert> + +#include <dune/common/exceptions.hh> + +#if HAVE_LAPACK + +// nonsymetric matrices +#define DGEEV_FORTRAN FC_FUNC (dgeev, DGEEV) + +// dsyev declaration (in liblapack) +extern "C" { + + /* + * + ** purpose + ** ======= + ** + ** xgeev computes for an N-by-N BASE DATA TYPE nonsymmetric matrix A, the + ** eigenvalues and, optionally, the left and/or right eigenvectors. + ** + ** The right eigenvector v(j) of A satisfies + ** A * v(j) = lambda(j) * v(j) + ** where lambda(j) is its eigenvalue. + ** The left eigenvector u(j) of A satisfies + ** u(j)**T * A = lambda(j) * u(j)**T + ** where u(j)**T denotes the transpose of u(j). + ** + ** The computed eigenvectors are normalized to have Euclidean norm + ** equal to 1 and largest component real. + ** + ** arguments + ** ========= + ** + ** jobvl (input) char + ** = 'n': left eigenvectors of a are not computed; + ** = 'v': left eigenvectors of a are computed. + ** + ** jobvr (input) char + ** = 'n': right eigenvectors of a are not computed; + ** = 'v': right eigenvectors of a are computed. + ** + ** n (input) long int + ** the order of the matrix v. v >= 0. + ** + ** a (input/output) BASE DATA TYPE array, dimension (lda,n) + ** on entry, the n-by-n matrix a. + ** on exit, a has been overwritten. + ** + ** lda (input) long int + ** the leading dimension of the array a. lda >= max(1,n). + ** + ** wr (output) BASE DATA TYPE array, dimension (n) + ** wi (output) BASE DATA TYPE array, dimension (n) + ** wr and wi contain the real and imaginary parts, + ** respectively, of the computed eigenvalues. complex + ** conjugate pairs of eigenvalues appear consecutively + ** with the eigenvalue having the positive imaginary part + ** first. + ** + ** vl (output) COMPLEX DATA TYPE array, dimension (ldvl,n) + ** if jobvl = 'v', the left eigenvectors u(j) are stored one + ** after another in the columns of vl, in the same order + ** as their eigenvalues. + ** if jobvl = 'n', vl is not referenced. + ** if the j-th eigenvalue is real, then u(j) = vl(:,j), + ** the j-th column of vl. + ** if the j-th and (j+1)-st eigenvalues form a complex + ** conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and + ** u(j+1) = vl(:,j) - i*vl(:,j+1). + ** + ** ldvl (input) long int + ** the leading dimension of the array vl. ldvl >= 1; if + ** jobvl = 'v', ldvl >= n. + ** + ** vr (output) COMPLEX DATA TYPE array, dimension (ldvr,n) + ** if jobvr = 'v', the right eigenvectors v(j) are stored one + ** after another in the columns of vr, in the same order + ** as their eigenvalues. + ** if jobvr = 'n', vr is not referenced. + ** if the j-th eigenvalue is real, then v(j) = vr(:,j), + ** the j-th column of vr. + ** if the j-th and (j+1)-st eigenvalues form a complex + ** conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and + ** v(j+1) = vr(:,j) - i*vr(:,j+1). + ** + ** ldvr (input) long int + ** the leading dimension of the array vr. ldvr >= 1; if + ** jobvr = 'v', ldvr >= n. + ** + ** work (workspace/output) BASE DATA TYPE array, dimension (max(1,lwork)) + ** on exit, if info = 0, work(1) returns the optimal lwork. + ** + ** lwork (input) long int + ** the dimension of the array work. lwork >= max(1,3*n), and + ** if jobvl = 'v' or jobvr = 'v', lwork >= 4*n. for good + ** performance, lwork must generally be larger. + ** + ** if lwork = -1, then a workspace query is assumed; the routine + ** only calculates the optimal size of the work array, returns + ** this value as the first entry of the work array, and no error + ** message related to lwork is issued by xerbla. + ** + ** info (output) long int + ** = 0: successful exit + ** < 0: if info = -i, the i-th argument had an illegal value. + ** > 0: if info = i, the qr algorithm failed to compute all the + ** eigenvalues, and no eigenvectors have been computed; + ** elements i+1:n of wr and wi contain eigenvalues which + ** have converged. + ** + **/ + + extern void DGEEV_FORTRAN(const char* jobvl, const char* jobvr, const long + int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, + const long int* ldvl, double* vr, const long int* ldvr, double* work, + const long int* lwork, const long int* info); + +} // end extern C +#endif + +namespace Dune { + + namespace DynamicMatrixHelp { + + void eigenValuesNonsymLapackCall( + const char* jobvl, const char* jobvr, const long + int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, + const long int* ldvl, double* vr, const long int* ldvr, double* work, + const long int* lwork, const long int* info) + { +#if HAVE_LAPACK + // call LAPACK dgeev + DGEEV_FORTRAN(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, + work, lwork, info); +#else + DUNE_THROW(NotImplemented,"eigenValuesNonsymLapackCall: LAPACK not found!"); +#endif + } + + } // end namespace FMatrixHelp + +} // end namespace Dune +#endif diff --git a/dune/common/dynmatrixev.hh b/dune/common/dynmatrixev.hh new file mode 100644 index 0000000000000000000000000000000000000000..5ad91d34712ce57e3dfd7741698cbd107ceda71c --- /dev/null +++ b/dune/common/dynmatrixev.hh @@ -0,0 +1,70 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_DYNMATRIXEIGENVALUES_HH +#define DUNE_DYNMATRIXEIGENVALUES_HH + +#include "dynmatrix.hh" + +namespace Dune { + + namespace DynamicMatrixHelp { + + // defined in fmatrixev_ext.cpp + extern void eigenValuesNonsymLapackCall( + const char* jobvl, const char* jobvr, const long + int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, + const long int* ldvl, double* vr, const long int* ldvr, double* work, + const long int* lwork, const long int* info); + + template <typename K, class C> + static void eigenValuesNonSym(const DynamicMatrix<K>& matrix, + DynamicVector<C>& eigenValues) + { + { + const long int N = matrix.rows(); + const char jobvl = 'n'; + const char jobvr = 'n'; + + + // matrix to put into dgeev + double matrixVector[N * N]; + + // copy matrix + int row = 0; + for(int i=0; i<N; ++i) + { + for(int j=0; j<N; ++j, ++row) + { + matrixVector[ row ] = matrix[ i ][ j ]; + } + } + + // working memory + double eigenR[N]; + double eigenI[N]; + double work[3*N]; + + // return value information + long int info = 0; + long int lwork = 3*N; + + // call LAPACK routine (see fmatrixev_ext.cc) + eigenValuesNonsymLapackCall(&jobvl, &jobvr, &N, &matrixVector[0], &N, + &eigenR[0], &eigenI[0], 0, &N, 0, &N, &work[0], + &lwork, &info); + + if( info != 0 ) + { + std::cerr << "For matrix " << matrix << " eigenvalue calculation failed! " << std::endl; + DUNE_THROW(InvalidStateException,"eigenValues: Eigenvalue calculation failed!"); + } + for (int i=0; i<N; ++i) + eigenValues[i] = std::complex<double>(eigenR[i], eigenI[i]); + } + } + + } + +} + +#endif diff --git a/dune/common/fmatrixev.cc b/dune/common/fmatrixev.cc index feba39854b3db2c43d4f909bd5bdc020f3499de1..d720d509caa8a6b43247e6bb30c7a47e2d8903a8 100644 --- a/dune/common/fmatrixev.cc +++ b/dune/common/fmatrixev.cc @@ -78,6 +78,111 @@ extern "C" { int* n, double* a, const long int* lda, double* w, double* work, const long int* lwork, long int* info); + /* + * + ** purpose + ** ======= + ** + ** xgeev computes for an N-by-N BASE DATA TYPE nonsymmetric matrix A, the + ** eigenvalues and, optionally, the left and/or right eigenvectors. + ** + ** The right eigenvector v(j) of A satisfies + ** A * v(j) = lambda(j) * v(j) + ** where lambda(j) is its eigenvalue. + ** The left eigenvector u(j) of A satisfies + ** u(j)**T * A = lambda(j) * u(j)**T + ** where u(j)**T denotes the transpose of u(j). + ** + ** The computed eigenvectors are normalized to have Euclidean norm + ** equal to 1 and largest component real. + ** + ** arguments + ** ========= + ** + ** jobvl (input) char + ** = 'n': left eigenvectors of a are not computed; + ** = 'v': left eigenvectors of a are computed. + ** + ** jobvr (input) char + ** = 'n': right eigenvectors of a are not computed; + ** = 'v': right eigenvectors of a are computed. + ** + ** n (input) long int + ** the order of the matrix v. v >= 0. + ** + ** a (input/output) BASE DATA TYPE array, dimension (lda,n) + ** on entry, the n-by-n matrix a. + ** on exit, a has been overwritten. + ** + ** lda (input) long int + ** the leading dimension of the array a. lda >= max(1,n). + ** + ** wr (output) BASE DATA TYPE array, dimension (n) + ** wi (output) BASE DATA TYPE array, dimension (n) + ** wr and wi contain the real and imaginary parts, + ** respectively, of the computed eigenvalues. complex + ** conjugate pairs of eigenvalues appear consecutively + ** with the eigenvalue having the positive imaginary part + ** first. + ** + ** vl (output) COMPLEX DATA TYPE array, dimension (ldvl,n) + ** if jobvl = 'v', the left eigenvectors u(j) are stored one + ** after another in the columns of vl, in the same order + ** as their eigenvalues. + ** if jobvl = 'n', vl is not referenced. + ** if the j-th eigenvalue is real, then u(j) = vl(:,j), + ** the j-th column of vl. + ** if the j-th and (j+1)-st eigenvalues form a complex + ** conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and + ** u(j+1) = vl(:,j) - i*vl(:,j+1). + ** + ** ldvl (input) long int + ** the leading dimension of the array vl. ldvl >= 1; if + ** jobvl = 'v', ldvl >= n. + ** + ** vr (output) COMPLEX DATA TYPE array, dimension (ldvr,n) + ** if jobvr = 'v', the right eigenvectors v(j) are stored one + ** after another in the columns of vr, in the same order + ** as their eigenvalues. + ** if jobvr = 'n', vr is not referenced. + ** if the j-th eigenvalue is real, then v(j) = vr(:,j), + ** the j-th column of vr. + ** if the j-th and (j+1)-st eigenvalues form a complex + ** conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and + ** v(j+1) = vr(:,j) - i*vr(:,j+1). + ** + ** ldvr (input) long int + ** the leading dimension of the array vr. ldvr >= 1; if + ** jobvr = 'v', ldvr >= n. + ** + ** work (workspace/output) BASE DATA TYPE array, dimension (max(1,lwork)) + ** on exit, if info = 0, work(1) returns the optimal lwork. + ** + ** lwork (input) long int + ** the dimension of the array work. lwork >= max(1,3*n), and + ** if jobvl = 'v' or jobvr = 'v', lwork >= 4*n. for good + ** performance, lwork must generally be larger. + ** + ** if lwork = -1, then a workspace query is assumed; the routine + ** only calculates the optimal size of the work array, returns + ** this value as the first entry of the work array, and no error + ** message related to lwork is issued by xerbla. + ** + ** info (output) long int + ** = 0: successful exit + ** < 0: if info = -i, the i-th argument had an illegal value. + ** > 0: if info = i, the qr algorithm failed to compute all the + ** eigenvalues, and no eigenvectors have been computed; + ** elements i+1:n of wr and wi contain eigenvalues which + ** have converged. + ** + **/ + + extern void DGEEV_FORTRAN(const char* jobvl, const char* jobvr, const long + int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, + const long int* ldvl, double* vr, const long int* ldvr, double* work, + const long int* lwork, const long int* info); + } // end extern C #endif @@ -98,6 +203,21 @@ namespace Dune { #endif } + void eigenValuesNonsymLapackCall( + const char* jobvl, const char* jobvr, const long + int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, + const long int* ldvl, double* vr, const long int* ldvr, double* work, + const long int* lwork, const long int* info) + { +#if HAVE_LAPACK + // call LAPACK dgeev + DGEEV_FORTRAN(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, + work, lwork, info); +#else + DUNE_THROW(NotImplemented,"eigenValuesNonsymLapackCall: LAPACK not found!"); +#endif + } + } // end namespace FMatrixHelp } // end namespace Dune diff --git a/dune/common/fmatrixev.hh b/dune/common/fmatrixev.hh index 2f244eae4980bd3184f10af89d1b5f05cbc7c223..cee1aa190ae14820d68b436d73a4d33a45a98f68 100644 --- a/dune/common/fmatrixev.hh +++ b/dune/common/fmatrixev.hh @@ -30,6 +30,12 @@ namespace Dune { int* n, double* a, const long int* lda, double* w, double* work, const long int* lwork, long int* info); + extern void eigenValuesNonsymLapackCall( + const char* jobvl, const char* jobvr, const long + int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, + const long int* ldvl, double* vr, const long int* ldvr, double* work, + const long int* lwork, const long int* info); + /** \brief calculates the eigenvalues of a symetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenvalues FieldVector that contains eigenvalues in @@ -122,6 +128,58 @@ namespace Dune { } } + template <int dim, typename K, class C> + static void eigenValuesNonSym(const FieldMatrix<K, dim, dim>& matrix, + FieldVector<C, dim>& eigenValues) + { + { + const long int N = dim ; + const char jobvl = 'n'; + const char jobvr = 'n'; + + // length of matrix vector + const long int w = N * N ; + + // matrix to put into dgeev + 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 eigenR[dim]; + double eigenI[dim]; + double work[3*dim]; + + // return value information + long int info = 0; + long int lwork = 3*dim; + + // call LAPACK routine (see fmatrixev_ext.cc) + eigenValuesNonsymLapackCall(&jobvl, &jobvr, &N, &matrixVector[0], &N, + &eigenR[0], &eigenI[0], 0, &N, 0, &N, &work[0], + &lwork, &info); + + if( info != 0 ) + { + std::cerr << "For matrix " << matrix << " eigenvalue calculation failed! " << std::endl; + DUNE_THROW(InvalidStateException,"eigenValues: Eigenvalue calculation failed!"); + } + for (int i=0; i<N; ++i) { + eigenValues[i].real = eigenR[i]; + eigenValues[i].imag = eigenI[i]; + } + } + + } + } // end namespace FMatrixHelp /** @} end documentation */ diff --git a/dune/common/test/Makefile.am b/dune/common/test/Makefile.am index 9b676024c87b486f8b0091777c2a88d3144c34d1..f6a7e38f1d1f73fb43f8062616996e75a5c69d03 100644 --- a/dune/common/test/Makefile.am +++ b/dune/common/test/Makefile.am @@ -11,6 +11,7 @@ TESTPROGS = \ diagonalmatrixtest \ dynmatrixtest \ dynvectortest \ + eigenvaluestest \ enumsettest \ fassigntest \ fmatrixtest \ @@ -161,6 +162,9 @@ dynmatrixtest_SOURCES = dynmatrixtest.cc dynvectortest_SOURCES = dynvectortest.cc +eigenvaluestest_SOURCES = eigenvaluestest.cc +eigenvaluestest_LDADD = $(LAPACK_LIBS) $(LDADD) $(BLAS_LIBS) $(LIBS) $(FLIBS) + fmatrixtest_SOURCES = fmatrixtest.cc fmatrixtest_LDADD = $(LAPACK_LIBS) $(LDADD) $(BLAS_LIBS) $(LIBS) $(FLIBS) diff --git a/dune/common/test/eigenvaluestest.cc b/dune/common/test/eigenvaluestest.cc new file mode 100644 index 0000000000000000000000000000000000000000..dea8906f6395eb8a0d695c5e195818d0bb96066e --- /dev/null +++ b/dune/common/test/eigenvaluestest.cc @@ -0,0 +1,259 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +//============================================================================== +//! +//! \file shapefunctions.hpp +//! +//! \date Nov 9 2011 +//! +//! \author Arne Morten Kvarving / SINTEF +//! +//! \brief Classes for shape functions. Loosely based on code in dune-grid-howto +//! +//============================================================================== + +#include <dune/common/fvector.hh> +#include <dune/common/dynmatrixev.hh> + +#include <complex> + + +//! \brief Represents a cardinal function on a line +template<class ctype, class rtype> +class LagrangeCardinalFunction +{ +public: + //! \brief Empty default constructor + LagrangeCardinalFunction() {} + + //! \brief Construct a cardinal function with the given nodes + //! \param[in] nodes_ The nodes + //! \param[in] i The node this function is associated with + LagrangeCardinalFunction(const std::vector<rtype>& nodes_, + size_t i) + : nodes(nodes_), node(i) {} + + //! \brief Evaluate the shape function + //! \param[in] local The local coordinates + rtype evaluateFunction(const ctype& local) const + { + rtype result = 1; + for (size_t i=0; i < nodes.size(); ++i) { + if (i != node) + result *= (local-nodes[i])/(nodes[node]-nodes[i]); + } + + return result; + } + + //! \brief Evaluate the derivative of the cardinal function + //! \param[in] local The local coordinates + rtype evaluateGradient(const ctype& local) const + { + rtype result = 0; + for (size_t i=0; i < nodes.size(); ++i) { + rtype f = 1; + for (int j=0; j < nodes.size(); ++j) { + if (i != j && j != node) + f *= (local-nodes[j])/(nodes[node]-nodes[j]); + } + result += f/(nodes[node]-nodes[i]); + } + + return result; + } + +private: + //! \brief The nodes + std::vector<rtype> nodes; + + size_t node; +}; + +//! \brief Represents a tensor-product of 1D functions +template<class rtype, class ctype, class ftype, int dim> +class TensorProductFunction +{ +public: + //! \brief The dimension of the function + enum { dimension = dim }; + + //! \brief Empty default constructor + TensorProductFunction() {} + + //! \brief Construct a tensor-product function + //! \param[in] funcs_ The functions + TensorProductFunction(const Dune::FieldVector<ftype, dim>& funcs_) + : funcs(funcs_) {} + + //! \brief Evaluate the function + //! \param[in] local The local coordinates + rtype evaluateFunction(const Dune::FieldVector<ctype,dim>& local) const + { + rtype result = 1; + for (int i=0; i < dim; ++i) + result *= funcs[i].evaluateFunction(local[i]); + + return result; + } + + Dune::FieldVector<rtype, dim> + evaluateGradient(const Dune::FieldVector<ctype,dim>& local) const + { + Dune::FieldVector<rtype, dim> result; + for (int i=0; i < dim; ++i) + result[i] = funcs[i].evaluateGradient(local[i]); + } +private: + Dune::FieldVector<ftype, dim> funcs; +}; + +template<int dim> +class PNShapeFunctionSet +{ +public: + typedef LagrangeCardinalFunction<double, double> CardinalFunction; + + typedef TensorProductFunction<double, double, CardinalFunction, dim> + ShapeFunction; + + PNShapeFunctionSet(int n1, int n2, int n3=0) + { + int dims[3] = {n1, n2, n3}; + cfuncs.resize(dim); + for (int i=0; i < dim; ++i) { + std::vector<double> grid; + grid = gaussLobattoLegendreGrid(dims[i]); + for (int j=0; j<dims[i]; ++j) + cfuncs[i].push_back(CardinalFunction(grid,j)); + } + int l=0; + Dune::FieldVector<CardinalFunction,dim> fs; + if (dim == 3) { + f.resize(n1*n2*n3); + for (int k=0; k < n3; ++k) { + for (int j=0; j < n2; ++j) + for (int i=0; i< n1; ++i) { + fs[0] = cfuncs[0][i]; + fs[1] = cfuncs[1][j]; + fs[2] = cfuncs[2][k]; + f[l++] = ShapeFunction(fs); + } + } + } else { + f.resize(n1*n2); + for (int j=0; j < n2; ++j) { + for (int i=0; i< n1; ++i) { + fs[0] = cfuncs[0][i]; + fs[1] = cfuncs[1][j]; + f[l++] = ShapeFunction(fs); + } + } + } + } + + //! \brief Obtain a given shape function + //! \param[in] i The requested shape function + const ShapeFunction& operator[](int i) const + { + return f[i]; + } + + int size() + { + return f.size(); + } +protected: + std::vector< std::vector<CardinalFunction> > cfuncs; + std::vector<ShapeFunction> f; + + double legendre(double x, int n) + { + std::vector<double> Ln; + Ln.resize(n+1); + Ln[0] = 1.f; + Ln[1] = x; + if( n > 1 ) { + for( int i=1; i<n; i++ ) + Ln[i+1] = (2*i+1.0)/(i+1.0)*x*Ln[i]-i/(i+1.0)*Ln[i-1]; + } + + return Ln[n]; + } + + double legendreDerivative(double x, int n) + { + std::vector<double> Ln; + Ln.resize(n+1); + + Ln[0] = 1.0; Ln[1] = x; + + if( (x == 1.0) || (x == -1.0) ) + return( pow(x,n-1)*n*(n+1.0)/2.0 ); + else { + for( int i=1; i<n; i++ ) + Ln[i+1] = (2.0*i+1.0)/(i+1.0)*x*Ln[i]-(double)i/(i+1.0)*Ln[i-1]; + return( (double)n/(1.0-x*x)*Ln[n-1]-n*x/(1-x*x)*Ln[n] ); + } + } + + + std::vector<double> gaussLegendreGrid(int n) + { + Dune::DynamicMatrix<double> A(n,n,0.0); + + A[0][1] = 1.f; + for (int i=1; i<n-1; ++i) { + A[i][i-1] = (double)i/(2.0*(i+1.0)-1.0); + A[i][i+1] = (double)(i+1.0)/(2*(i+1.0)-1.0); + } + A[n-1][n-2] = (n-1.0)/(2.0*n-1.0); + + Dune::DynamicVector<std::complex<double> > eigenValues(n); + Dune::DynamicMatrixHelp::eigenValuesNonSym(A, eigenValues); + + std::vector<double> result(n); + for (int i=0; i < n; ++i) + result[i] = std::real(eigenValues[i]); + std::sort(result.begin(),result.begin()+n); + + return result; + } + + std::vector<double> gaussLobattoLegendreGrid(int n) + { + assert(n > 1); + const double tolerance = 1.e-15; + + std::vector<double> result(n); + result[0] = 0.0; + result[n-1] = 1.0; + if (n == 3) + result[1] = 0.5; + + if (n < 4) + return result; + + std::vector<double> glgrid = gaussLegendreGrid(n-1); + for (int i=1; i<n-1; ++i) { + result[i] = (glgrid[i-1]+glgrid[i])/2.0; + double old = 0.0; + while (std::abs(old-result[i]) > tolerance) { + old = result[i]; + double L = legendre(old, n-1); + double Ld = legendreDerivative(old, n-1); + result[i] += (1.0-old*old)*Ld/((n-1.0)*n*L); + } + result[i] = (result[i]+1.0)/2.0; + } + + return result; + } +}; + +int main() +{ + // Not really a test but better than nothing. + PNShapeFunctionSet<2> lbasis(2, 3); + return 0; +}