FourthOrderTensor.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #ifndef _FOURTHORDERTENSOR_HPP_
00030 #define _FOURTHORDERTENSOR_HPP_
00031 
00032 #include <cassert>
00033 #include <vector>
00034 
00035 #include <boost/numeric/ublas/vector.hpp>
00036 #include <boost/numeric/ublas/matrix.hpp>
00037 using namespace boost::numeric::ublas;
00038 #include "Exception.hpp"
00039 
00045 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00046 class FourthOrderTensor
00047 {
00048 private:
00049 
00050     std::vector<double> mData;  
00058     unsigned GetVectorIndex(unsigned M, unsigned N, unsigned P, unsigned Q)
00059     {
00060         assert(M<DIM1);
00061         assert(N<DIM2);
00062         assert(P<DIM3);
00063         assert(Q<DIM4);
00064         return M + DIM1*N + DIM1*DIM2*P + DIM1*DIM2*DIM3*Q;
00065     }
00066 
00067 public:
00068 
00072     FourthOrderTensor();
00073 
00082     template<unsigned CONTRACTED_DIM>
00083     void SetAsContractionOnFirstDimension(const c_matrix<double,DIM1,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<CONTRACTED_DIM,DIM2,DIM3,DIM4>& rTensor);
00084 
00085 
00094     template<unsigned CONTRACTED_DIM>
00095     void SetAsContractionOnSecondDimension(const c_matrix<double,DIM2,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,CONTRACTED_DIM,DIM3,DIM4>& rTensor);
00096 
00105     template<unsigned CONTRACTED_DIM>
00106     void SetAsContractionOnThirdDimension(const c_matrix<double,DIM3,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,CONTRACTED_DIM,DIM4>& rTensor);
00107 
00116     template<unsigned CONTRACTED_DIM>
00117     void SetAsContractionOnFourthDimension(const c_matrix<double,DIM4,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,DIM3,CONTRACTED_DIM>& rTensor);
00118 
00127     double& operator()(unsigned M, unsigned N, unsigned P, unsigned Q);
00128 
00132     void Zero();
00133 
00137     std::vector<double>& rGetData()
00138     {
00139         return mData;
00140     }
00141 };
00142 
00144 // Implementation (lots of possibilities for the dimensions so no point with explicit instantiation)
00146 
00147 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00148 FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::FourthOrderTensor()
00149 {
00150     unsigned size = DIM1*DIM2*DIM3*DIM4;
00151     mData.resize(size, 0.0);
00152 }
00153 
00154 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00155 template<unsigned CONTRACTED_DIM>
00156 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnFirstDimension(const c_matrix<double,DIM1,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<CONTRACTED_DIM,DIM2,DIM3,DIM4>& rTensor)
00157 {
00158     Zero();
00159 
00160     std::vector<double>::iterator iter = mData.begin();
00161     std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin();
00162 
00163     for (unsigned d=0; d<DIM4; d++)
00164     {
00165         for (unsigned c=0; c<DIM3; c++)
00166         {
00167             for (unsigned b=0; b<DIM2; b++)
00168             {
00169                 for (unsigned a=0; a<DIM1; a++)
00170                 {
00171                     for (unsigned N=0; N<CONTRACTED_DIM; N++)
00172                     {
00173                         /*
00174                          * The following just does
00175                          *
00176                          * mData[GetVectorIndex(a,b,c,d)] += rMatrix(a,N) * rTensor(N,b,c,d);
00177                          *
00178                          * but more efficiently using iterators into the data vector, not
00179                          * using random access.
00180                          */
00181                         *iter += rMatrix(a,N) * *other_tensor_iter;
00182                         other_tensor_iter++;
00183                     }
00184 
00185                     iter++;
00186 
00187                     if (a != DIM1-1)
00188                     {
00189                         other_tensor_iter -= CONTRACTED_DIM;
00190                     }
00191                 }
00192             }
00193         }
00194     }
00195 }
00196 
00197 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00198 template<unsigned CONTRACTED_DIM>
00199 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnSecondDimension(const c_matrix<double,DIM2,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,CONTRACTED_DIM,DIM3,DIM4>& rTensor)
00200 {
00201     Zero();
00202 
00203     std::vector<double>::iterator iter = mData.begin();
00204     std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin();
00205 
00206     for (unsigned d=0; d<DIM4; d++)
00207     {
00208         for (unsigned c=0; c<DIM3; c++)
00209         {
00210             for (unsigned b=0; b<DIM2; b++)
00211             {
00212                 for (unsigned N=0; N<CONTRACTED_DIM; N++)
00213                 {
00214                     for (unsigned a=0; a<DIM1; a++)
00215                     {
00216                         /*
00217                          * The following just does
00218                          *
00219                          * mData[GetVectorIndex(a,b,c,d)] += rMatrix(b,N) * rTensor(a,N,c,d);
00220                          *
00221                          * but more efficiently using iterators into the data vector, not
00222                          * using random access.
00223                          */
00224                         *iter += rMatrix(b,N) * *other_tensor_iter;
00225                         iter++;
00226                         other_tensor_iter++;
00227                     }
00228 
00229                     if (N != CONTRACTED_DIM-1)
00230                     {
00231                         iter -= DIM1;
00232                     }
00233                 }
00234                 if (b != DIM2-1)
00235                 {
00236                     other_tensor_iter -= CONTRACTED_DIM*DIM1;
00237                 }
00238             }
00239         }
00240     }
00241 }
00242 
00243 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00244 template<unsigned CONTRACTED_DIM>
00245 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnThirdDimension(const c_matrix<double,DIM3,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,CONTRACTED_DIM,DIM4>& rTensor)
00246 {
00247     Zero();
00248 
00249     std::vector<double>::iterator iter = mData.begin();
00250     std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin();
00251 
00252     for (unsigned d=0; d<DIM4; d++)
00253     {
00254         for (unsigned c=0; c<DIM3; c++)
00255         {
00256             for (unsigned N=0; N<CONTRACTED_DIM; N++)
00257             {
00258                 for (unsigned b=0; b<DIM2; b++)
00259                 {
00260                     for (unsigned a=0; a<DIM1; a++)
00261                     {
00262                         /*
00263                          * The following just does
00264                          *
00265                          * mData[GetVectorIndex(a,b,c,d)] += rMatrix(c,N) * rTensor(a,b,N,d);
00266                          *
00267                          * but more efficiently using iterators into the data vector, not
00268                          * using random access.
00269                          */
00270                         *iter += rMatrix(c,N) * *other_tensor_iter;
00271                         iter++;
00272                         other_tensor_iter++;
00273                     }
00274                 }
00275 
00276                 if (N != CONTRACTED_DIM-1)
00277                 {
00278                     iter -= DIM1*DIM2;
00279                 }
00280             }
00281 
00282             if (c != DIM3-1)
00283             {
00284                 other_tensor_iter -= CONTRACTED_DIM*DIM1*DIM2;
00285             }
00286         }
00287     }
00288 }
00289 
00290 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00291 template<unsigned CONTRACTED_DIM>
00292 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::SetAsContractionOnFourthDimension(const c_matrix<double,DIM4,CONTRACTED_DIM>& rMatrix, FourthOrderTensor<DIM1,DIM2,DIM3,CONTRACTED_DIM>& rTensor)
00293 {
00294     Zero();
00295 
00296     std::vector<double>::iterator iter = mData.begin();
00297     std::vector<double>::iterator other_tensor_iter = rTensor.rGetData().begin();
00298 
00299     for (unsigned d=0; d<DIM4; d++)
00300     {
00301         for (unsigned N=0; N<CONTRACTED_DIM; N++)
00302         {
00303             for (unsigned c=0; c<DIM3; c++)
00304             {
00305                 for (unsigned b=0; b<DIM2; b++)
00306                 {
00307                     for (unsigned a=0; a<DIM1; a++)
00308                     {
00309                         /*
00310                          * The following just does
00311                          *
00312                          * mData[GetVectorIndex(a,b,c,d)] += rMatrix(d,N) * rTensor(a,b,c,N);
00313                          *
00314                          * but more efficiently using iterators into the data vector, not
00315                          * using random access.
00316                          */
00317                         *iter += rMatrix(d,N) * *other_tensor_iter;
00318 
00319                         iter++;
00320                         other_tensor_iter++;
00321                     }
00322                 }
00323             }
00324 
00325             if (N != CONTRACTED_DIM-1)
00326             {
00327                 iter-= DIM1*DIM2*DIM3;
00328             }
00329         }
00330 
00331         other_tensor_iter -= CONTRACTED_DIM*DIM1*DIM2*DIM3;
00332     }
00333 }
00334 
00335 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00336 double& FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::operator()(unsigned M, unsigned N, unsigned P, unsigned Q)
00337 {
00338     assert(M<DIM1);
00339     assert(N<DIM2);
00340     assert(P<DIM3);
00341     assert(Q<DIM4);
00342 
00343     return mData[GetVectorIndex(M,N,P,Q)];
00344 }
00345 
00346 template<unsigned DIM1, unsigned DIM2, unsigned DIM3, unsigned DIM4>
00347 void FourthOrderTensor<DIM1,DIM2,DIM3,DIM4>::Zero()
00348 {
00349     for (unsigned i=0; i<mData.size(); i++)
00350     {
00351         mData[i] = 0.0;
00352     }
00353 }
00354 
00355 #endif //_FOURTHORDERTENSOR_HPP_
Generated on Thu Dec 22 13:00:07 2011 for Chaste by  doxygen 1.6.3