OpenWalnut  1.4.0
WTensorSym.h
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #ifndef WTENSORSYM_H
00026 #define WTENSORSYM_H
00027 
00028 #include <iostream>
00029 
00030 #include <boost/array.hpp>
00031 
00032 #include "WTensorMeta.h"
00033 #include "WTensorBase.h"
00034 
00035 // ############################# class WTensorSym<> #############################################
00036 
00037 /**
00038  * Implements a symmetric tensor that has the same number of components in every
00039  * direction. A symmetric tensor has the same value for every permutation of the indices.
00040  *
00041  * For example, t(i,j) = t(j,i) for a tensor of order 2, and t(i,j,k) = t(j,i,k) = t(i,k,j)
00042  * = t(j,k,i) = t(k,i,j) = t(k,j,i) for a tensor of order 3.
00043  *
00044  * \tparam order The order of the tensor.
00045  * \tparam dim The dimension of the tensor, i.e. the number of components
00046  * in each direction.
00047  * \tparam Data_T The datatype of the components, double by default.
00048  *
00049  * \note The dimension may never be 0.
00050  * \note The type Data_T may not throw exceptions on construction, destruction or
00051  * during any assignment operator.
00052  *
00053  * Access to specific elements of the tensor can be achieved in 2 ways:
00054  *
00055  * - operator (), whose number of parameters matches the template parameter order.
00056  * - operator [], whose parameter is either an array or a std::vector of appropriate size.
00057  *
00058  * \note The datatype of the array or std::vector can be any type castable to std::size_t.
00059  * \note There is no bounds checking for the array version of operator [].
00060  * \note Operator () is not supported for orders larger than 6.
00061  *
00062  * This class optimizes memory usage. For example, for a symmetric tensor of order 2 and
00063  * dimension 3, only 6 values (instead of 9) need to be stored. However, there is additional
00064  * memory overhead per class (i.e. per allocation of the template parameters), which is of
00065  * constant size and thus does not depend on the number of instances.
00066  *
00067  * Usage and operators are the same as with WTensor. Note that changes to an
00068  * element t(i,j,k,...) also change every element whose indices are a permutation of i,j,k... .
00069  * \see WTensor
00070  */
00071 template< std::size_t order, std::size_t dim, typename Data_T = double >
00072 class WTensorSym : public WTensorFunc< WTensorBaseSym, order, dim, Data_T >
00073 {
00074 public:
00075     /**
00076      * Default constructor of the symmetric tensor.
00077      */
00078     WTensorSym();
00079 
00080     /**
00081      * Constructs and initializes the symmetrical Tensor with a WValue.
00082      *
00083      * \note The same ordering as for the data member is required.
00084      *
00085      * \param data The components in same ordering as for the data member \c m_data is required, (\see m_data).
00086      */
00087     explicit WTensorSym( const WValue< Data_T >& data );
00088 
00089     /**
00090      * Constructs and initializes the symmetrical Tensor with a boost array.
00091      *
00092      * \note The same ordering as for the data member is required.
00093      *
00094      * \param data The components in same ordering as for the data member \c m_data is required, (\see m_data).
00095      */
00096     explicit WTensorSym( const boost::array< Data_T, WTensorBaseSym< order, dim, Data_T >::dataSize >& data );
00097 
00098     /**
00099      * Evaluate - for a given gradient - the spherical function represented by this symmetric tensor.
00100      *
00101      * \tparam The type that stores the gradient, must implement operator [].
00102      *
00103      * \param gradient The normalized vector that represents the gradient direction.
00104      *
00105      * \note If the gradient is not normalized, the result is undefined.
00106      *
00107      * Thanks to CHeine for the idea for this algorithm.
00108      *
00109      * \return The function value on the sphere for this tensor and the given gradient. 
00110      */
00111     Data_T evaluateSphericalFunction( WValue< Data_T > const& gradient ) const;
00112 
00113     /**
00114      * Evaluate - for a given gradient - the spherical function represented by this symmetric tensor.
00115      *
00116      * \tparam The type that stores the gradient, must implement operator [].
00117      *
00118      * \param gradient The normalized vector that represents the gradient direction.
00119      *
00120      * \note If the gradient is not normalized, the result is undefined.
00121      *
00122      * Thanks to CHeine for the idea for this algorithm.
00123      *
00124      * \return The function value on the sphere for this tensor and the given gradient. 
00125      */
00126     Data_T evaluateSphericalFunction( WMatrixFixed< Data_T, 3, 1 > const& gradient ) const;
00127 
00128 protected:
00129 private:
00130     using WTensorFunc< WTensorBaseSym, order, dim, Data_T >::m_data;
00131 };
00132 
00133 template< std::size_t order, std::size_t dim, typename Data_T >
00134 WTensorSym< order, dim, Data_T >::WTensorSym()
00135     : WTensorFunc< WTensorBaseSym, order, dim, Data_T >()
00136 {
00137 }
00138 
00139 template< std::size_t order, std::size_t dim, typename Data_T >
00140 WTensorSym< order, dim, Data_T >::WTensorSym( const WValue< Data_T >& data )
00141     : WTensorFunc< WTensorBaseSym, order, dim, Data_T >( data )
00142 {
00143 }
00144 
00145 template< std::size_t order, std::size_t dim, typename Data_T >
00146 WTensorSym< order, dim, Data_T >::WTensorSym( const boost::array< Data_T, WTensorBaseSym< order, dim, Data_T >::dataSize >& data )
00147     : WTensorFunc< WTensorBaseSym, order, dim, Data_T >( data )
00148 {
00149 }
00150 
00151 template< std::size_t order, std::size_t dim, typename Data_T >
00152 Data_T WTensorSym< order, dim, Data_T >::evaluateSphericalFunction( WValue< Data_T > const& gradient ) const
00153 {
00154     Data_T const* tens = &m_data[ 0 ];
00155     Data_T const* grad = &gradient[ 0 ];
00156     return WRecursiveTensorEvaluation< Data_T, order, 0, dim, 0 >::evaluate( tens, grad, 1.0 ) * WFactorial< order >::value;
00157 }
00158 
00159 template< std::size_t order, std::size_t dim, typename Data_T >
00160 Data_T WTensorSym< order, dim, Data_T >::evaluateSphericalFunction( WMatrixFixed< Data_T, 3, 1 > const& gradient ) const
00161 {
00162     Data_T const* tens = &m_data[ 0 ];
00163     Data_T const* grad = &gradient[ 0 ];
00164     return WRecursiveTensorEvaluation< Data_T, order, 0, dim, 0 >::evaluate( tens, grad, 1.0 ) * WFactorial< order >::value;
00165 }
00166 
00167 // ######################## stream output operators #################################
00168 
00169 /**
00170  * Write a symmetric tensor of order 0 to an output stream.
00171  *
00172  * \param o An output stream.
00173  * \param t A WTensorSym.
00174  *
00175  * \return The output stream.
00176  */
00177 template< std::size_t dim, typename Data_T >
00178 std::ostream& operator << ( std::ostream& o, WTensorSym< 0, dim, Data_T > const& t )
00179 {
00180     o << t() << std::endl;
00181     return o;
00182 }
00183 
00184 /**
00185  * Write a symmetric tensor of order 1 to an output stream.
00186  *
00187  * \param o An output stream.
00188  * \param t A WTensorSym.
00189  *
00190  * \return The output stream.
00191  */
00192 template< std::size_t dim, typename Data_T >
00193 std::ostream& operator << ( std::ostream& o, WTensorSym< 1, dim, Data_T > const& t )
00194 {
00195     for( std::size_t k = 0; k < dim; ++k )
00196     {
00197         o << t( k ) << " ";
00198     }
00199     o << std::endl;
00200     return o;
00201 }
00202 
00203 /**
00204  * Write a symmetric tensor of order 2 to an output stream.
00205  *
00206  * \param o An output stream.
00207  * \param t A WTensorSym.
00208  *
00209  * \return The output stream.
00210  */
00211 template< std::size_t dim, typename Data_T >
00212 std::ostream& operator << ( std::ostream& o, WTensorSym< 2, dim, Data_T > const& t )
00213 {
00214     for( std::size_t k = 0; k < dim; ++k )
00215     {
00216         for( std::size_t l = 0; l < dim; ++l )
00217         {
00218             o << t( k, l ) << " ";
00219         }
00220         o << std::endl;
00221     }
00222     return o;
00223 }
00224 // ######################## a utility function #################################
00225 
00226 /**
00227  * This calculates the multiplicity of the elements of a 3-dimensional
00228  * symmetric tensor. (see Özarslan's paper from 2003)
00229  * In a (super-)symmetric tensor, all permutations of a given set of Indices
00230  * i_1, i_2, ... i_order ( i_j in 0,1,2 ) refer to the same data element.
00231  * This means each data element can be identified by the amount of 0's, 1's
00232  * and 2's in its index list. Permutations do not change these amounts, thus
00233  * different data elements must differ in amount of 0's, 1's and 2's. The number of
00234  * permutations that exist on the index list of a data element is its multiplicity.
00235  *
00236  * \param order The order of the tensor.
00237  * \param numZeros How many elements of the permutation equal 0.
00238  * \param numOnes How many elements of the permutation equal 1.
00239  * \param numTwos How many elements of the permutation equal 2.
00240  */
00241 std::size_t calcSupersymmetricTensorMultiplicity( std::size_t order, std::size_t numZeros, std::size_t numOnes, std::size_t numTwos );
00242 
00243 #endif  // WTENSORSYM_H