OpenWalnut 1.3.1
|
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