Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #ifndef _FOURTHORDERTENSOR_HPP_ 00037 #define _FOURTHORDERTENSOR_HPP_ 00038 00039 #include <cassert> 00040 #include <vector> 00041 00042 #include <boost/numeric/ublas/vector.hpp> 00043 #include <boost/numeric/ublas/matrix.hpp> 00044 using namespace boost::numeric::ublas; 00045 #include "Exception.hpp" 00046 00052 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00053 class FourthOrderTensor 00054 { 00055 private: 00056 00057 std::vector<double> mData; 00065 unsigned GetVectorIndex(unsigned M, unsigned N, unsigned P, unsigned Q) 00066 { 00067 assert(M<DIM1); 00068 assert(N<DIM2); 00069 assert(P<DIM3); 00070 assert(Q<DIM4); 00071 return M + DIM1*N + DIM1*DIM2*P + DIM1*DIM2*DIM3*Q; 00072 } 00073 00074 public: 00075 00079 FourthOrderTensor(); 00080 00089 template<unsigned CONTRACTED_DIM> 00090 void SetAsContractionOnFirstDimension(const c_matrix<double,DIM1,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<CONTRACTED_DIM,DIM2,DIM3,DIM4>& rTensor); 00091 00092 00101 template<unsigned CONTRACTED_DIM> 00102 void SetAsContractionOnSecondDimension(const c_matrix<double,DIM2,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,CONTRACTED_DIM,DIM3,DIM4>& rTensor); 00103 00112 template<unsigned CONTRACTED_DIM> 00113 void SetAsContractionOnThirdDimension(const c_matrix<double,DIM3,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,CONTRACTED_DIM,DIM4>& rTensor); 00114 00123 template<unsigned CONTRACTED_DIM> 00124 void SetAsContractionOnFourthDimension(const c_matrix<double,DIM4,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,DIM3,CONTRACTED_DIM>& rTensor); 00125 00134 double& operator()(unsigned M, unsigned N, unsigned P, unsigned Q); 00135 00139 void Zero(); 00140 00144 std::vector<double>& rGetData() 00145 { 00146 return mData; 00147 } 00148 }; 00149 00151 // Implementation (lots of possibilities for the dimensions so no point with explicit instantiation) 00153 00154 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00155 FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::FourthOrderTensor() 00156 { 00157 unsigned size = DIM1*DIM2*DIM3*DIM4; 00158 mData.resize(size, 0.0); 00159 } 00160 00161 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00162 template<unsigned CONTRACTED_DIM> 00163 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnFirstDimension(const c_matrix<double,DIM1,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<CONTRACTED_DIM,DIM2,DIM3,DIM4>& rTensor) 00164 { 00165 Zero(); 00166 00167 std::vector<double>::iterator iter = mData.begin(); 00168 std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin(); 00169 00170 for (unsigned d=0; d<DIM4; d++) 00171 { 00172 for (unsigned c=0; c<DIM3; c++) 00173 { 00174 for (unsigned b=0; b<DIM2; b++) 00175 { 00176 for (unsigned a=0; a<DIM1; a++) 00177 { 00178 for (unsigned N=0; N<CONTRACTED_DIM; N++) 00179 { 00180 /* 00181 * The following just does 00182 * 00183 * mData[GetVectorIndex(a,b,c,d)] += rMatrix(a,N) * rTensor(N,b,c,d); 00184 * 00185 * but more efficiently using iterators into the data vector, not 00186 * using random access. 00187 */ 00188 *iter += rMatrix(a,N) * *other_tensor_iter; 00189 other_tensor_iter++; 00190 } 00191 00192 iter++; 00193 00194 if (a != DIM1-1) 00195 { 00196 other_tensor_iter -= CONTRACTED_DIM; 00197 } 00198 } 00199 } 00200 } 00201 } 00202 } 00203 00204 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00205 template<unsigned CONTRACTED_DIM> 00206 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnSecondDimension(const c_matrix<double,DIM2,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,CONTRACTED_DIM,DIM3,DIM4>& rTensor) 00207 { 00208 Zero(); 00209 00210 std::vector<double>::iterator iter = mData.begin(); 00211 std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin(); 00212 00213 for (unsigned d=0; d<DIM4; d++) 00214 { 00215 for (unsigned c=0; c<DIM3; c++) 00216 { 00217 for (unsigned b=0; b<DIM2; b++) 00218 { 00219 for (unsigned N=0; N<CONTRACTED_DIM; N++) 00220 { 00221 for (unsigned a=0; a<DIM1; a++) 00222 { 00223 /* 00224 * The following just does 00225 * 00226 * mData[GetVectorIndex(a,b,c,d)] += rMatrix(b,N) * rTensor(a,N,c,d); 00227 * 00228 * but more efficiently using iterators into the data vector, not 00229 * using random access. 00230 */ 00231 *iter += rMatrix(b,N) * *other_tensor_iter; 00232 iter++; 00233 other_tensor_iter++; 00234 } 00235 00236 if (N != CONTRACTED_DIM-1) 00237 { 00238 iter -= DIM1; 00239 } 00240 } 00241 if (b != DIM2-1) 00242 { 00243 other_tensor_iter -= CONTRACTED_DIM*DIM1; 00244 } 00245 } 00246 } 00247 } 00248 } 00249 00250 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00251 template<unsigned CONTRACTED_DIM> 00252 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnThirdDimension(const c_matrix<double,DIM3,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,CONTRACTED_DIM,DIM4>& rTensor) 00253 { 00254 Zero(); 00255 00256 std::vector<double>::iterator iter = mData.begin(); 00257 std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin(); 00258 00259 for (unsigned d=0; d<DIM4; d++) 00260 { 00261 for (unsigned c=0; c<DIM3; c++) 00262 { 00263 for (unsigned N=0; N<CONTRACTED_DIM; N++) 00264 { 00265 for (unsigned b=0; b<DIM2; b++) 00266 { 00267 for (unsigned a=0; a<DIM1; a++) 00268 { 00269 /* 00270 * The following just does 00271 * 00272 * mData[GetVectorIndex(a,b,c,d)] += rMatrix(c,N) * rTensor(a,b,N,d); 00273 * 00274 * but more efficiently using iterators into the data vector, not 00275 * using random access. 00276 */ 00277 *iter += rMatrix(c,N) * *other_tensor_iter; 00278 iter++; 00279 other_tensor_iter++; 00280 } 00281 } 00282 00283 if (N != CONTRACTED_DIM-1) 00284 { 00285 iter -= DIM1*DIM2; 00286 } 00287 } 00288 00289 if (c != DIM3-1) 00290 { 00291 other_tensor_iter -= CONTRACTED_DIM*DIM1*DIM2; 00292 } 00293 } 00294 } 00295 } 00296 00297 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00298 template<unsigned CONTRACTED_DIM> 00299 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnFourthDimension(const c_matrix<double,DIM4,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,DIM3,CONTRACTED_DIM>& rTensor) 00300 { 00301 Zero(); 00302 00303 std::vector<double>::iterator iter = mData.begin(); 00304 std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin(); 00305 00306 for (unsigned d=0; d<DIM4; d++) 00307 { 00308 for (unsigned N=0; N<CONTRACTED_DIM; N++) 00309 { 00310 for (unsigned c=0; c<DIM3; c++) 00311 { 00312 for (unsigned b=0; b<DIM2; b++) 00313 { 00314 for (unsigned a=0; a<DIM1; a++) 00315 { 00316 /* 00317 * The following just does 00318 * 00319 * mData[GetVectorIndex(a,b,c,d)] += rMatrix(d,N) * rTensor(a,b,c,N); 00320 * 00321 * but more efficiently using iterators into the data vector, not 00322 * using random access. 00323 */ 00324 *iter += rMatrix(d,N) * *other_tensor_iter; 00325 00326 iter++; 00327 other_tensor_iter++; 00328 } 00329 } 00330 } 00331 00332 if (N != CONTRACTED_DIM-1) 00333 { 00334 iter-= DIM1*DIM2*DIM3; 00335 } 00336 } 00337 00338 other_tensor_iter -= CONTRACTED_DIM*DIM1*DIM2*DIM3; 00339 } 00340 } 00341 00342 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00343 double& FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::operator()(unsigned M, unsigned N, unsigned P, unsigned Q) 00344 { 00345 assert(M<DIM1); 00346 assert(N<DIM2); 00347 assert(P<DIM3); 00348 assert(Q<DIM4); 00349 00350 return mData[GetVectorIndex(M,N,P,Q)]; 00351 } 00352 00353 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4> 00354 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::Zero() 00355 { 00356 for (unsigned i=0; i<mData.size(); i++) 00357 { 00358 mData[i] = 0.0; 00359 } 00360 } 00361 00362 #endif //_FOURTHORDERTENSOR_HPP_