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