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