// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_RANNACHER_TUREK_3D_LOCALBASIS_HH
#define DUNE_RANNACHER_TUREK_3D_LOCALBASIS_HH

#include <vector>

#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>

#include <dune/localfunctions/common/localbasis.hh>

namespace Dune
{

  template< class D, class R >
  class RannacherTurek3DLocalBasis
  {
    static const int coefficients[ 6 ][ 6 ];

  public:
    typedef LocalBasisTraits< D, 3, FieldVector< D, 3 >,
        R, 1, FieldVector< R, 1 >,
        FieldMatrix< R, 1, 3 > > Traits;

    //! \brief number of shape functions
    unsigned int size () const
    {
      return 6;
    }

    //! \brief evaluate all shape functions
    inline void evaluateFunction ( const typename Traits::DomainType &in,
                                   std::vector< typename Traits::RangeType > &out ) const
    {
      typedef typename Traits::RangeFieldType RangeFieldType;
      RangeFieldType y[ 6 ] = { 1, in[ 0 ], in[ 1 ], in[ 2 ],
                                in[ 0 ]*in[ 0 ] - in[ 1 ]*in[ 1 ],
                                in[ 1 ]*in[ 1 ] - in[ 2 ]*in[ 2 ] };
      out.resize( size() );
      for( unsigned int i = 0; i < size(); ++i )
      {
        out[ i ] = RangeFieldType( 0 );
        for( unsigned int j = 0; j < 6; ++j )
          out[ i ] += coefficients[ i ][ j ]*y[ j ];
        out[ i ] /= RangeFieldType( 3 );
      }
    }

    //! \brief evaluate jacobian of all shape functions
    inline void evaluateJacobian ( const typename Traits::DomainType &in,
                                   std::vector< typename Traits::JacobianType > &out ) const
    {
      typedef typename Traits::RangeFieldType RangeFieldType;
      RangeFieldType y0[ 5 ] = { 1, 0, 0, 2*in[ 0 ], 0 };
      RangeFieldType y1[ 5 ] = { 0, 1, 0, -2*in[ 1 ], 2*in[ 1 ] };
      RangeFieldType y2[ 5 ] = { 0, 0, 1, 0, -2*in[ 2 ] };

      out.resize( size() );
      for( unsigned int i = 0; i < size(); ++i )
      {
        out[ i ] = RangeFieldType( 0 );
        for( unsigned int j = 0; j < 5; ++j )
        {
          out[ i ][ 0 ][ 0 ] += coefficients[ i ][ j+1 ]*y0[ j ];
          out[ i ][ 0 ][ 1 ] += coefficients[ i ][ j+1 ]*y1[ j ];
          out[ i ][ 0 ][ 2 ] += coefficients[ i ][ j+1 ]*y2[ j ];
        }
        out[ i ] /= RangeFieldType( 3 );
      }
    }

    //! \brief polynomial order of the shape functions
    unsigned int order () const
    {
      return 2;
    }
  };



  // RannacherTurek3DLocalBasis::coefficients
  // ----------------------------------------

  template< class D, class R >
  const int RannacherTurek3DLocalBasis< D, R >
  ::coefficients[ 6 ][ 6 ] = {{  2, -7,  2,  2,  4,  2 },
                              { -1, -1,  2,  2,  4,  2 },
                              {  2,  2, -7,  2, -2,  2 },
                              { -1,  2, -1,  2, -2,  2 },
                              {  2,  2,  2, -7, -2, -4 },
                              { -1,  2,  2, -1, -2, -4 }};

} //namespace Dune

#endif // #ifndef DUNE_RANNACHER_TUREK_3D_LOCALBASIS_HH
