AbstractTetrahedralElement.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 #include "UblasCustomFunctions.hpp"
00030 
00031 #include "AbstractTetrahedralElement.hpp"
00032 
00033 #include "Exception.hpp"
00034 
00035 #include <cassert>
00036 
00038 // Implementation
00040 
00041 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00042 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::RefreshJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian)
00043 {
00044     if (this->mIsDeleted)
00045     {
00046         EXCEPTION("Attempting to Refresh a deleted element");
00047     }
00048     for (unsigned i=0; i<SPACE_DIM; i++)
00049     {
00050         for (unsigned j=0; j!=ELEMENT_DIM; j++) // Does a j<ELEMENT_DIM without ever having to test j<0U (#186: pointless comparison of unsigned integer with zero)
00051         {
00052             rJacobian(i,j) = this->GetNodeLocation(j+1,i) - this->GetNodeLocation(0,i);
00053         }
00054     }
00055 }
00056 
00057 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00058 AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::AbstractTetrahedralElement(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes)
00059     : AbstractElement<ELEMENT_DIM, SPACE_DIM>(index, rNodes)
00060 {
00061     // Sanity checking
00062     unsigned num_vectices = ELEMENT_DIM+1;
00063 
00064     // This is so we know it's the first time of asking
00065     // Create Jacobian
00066     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00067 
00068     if (SPACE_DIM == ELEMENT_DIM)
00069     {
00070         double det;
00071         try
00072         {
00073             CalculateJacobian(jacobian, det);
00074         }
00075         catch (Exception)
00076         {
00077             // if the Jacobian is negative the orientation of the element is probably
00078             // wrong, so swap the last two nodes around.
00079 
00080             this->mNodes[num_vectices-1] = rNodes[num_vectices-2];
00081             this->mNodes[num_vectices-2] = rNodes[num_vectices-1];
00082 
00083             CalculateJacobian(jacobian, det);
00084             // If determinant < 0 then element nodes are listed clockwise.
00085             // We want them anticlockwise.
00086             assert(det > 0.0);
00087         }
00088     }
00089     // else - don't bother working out the chirality
00090 }
00091 
00092 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00093 AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::AbstractTetrahedralElement(unsigned index)
00094     : AbstractElement<ELEMENT_DIM,SPACE_DIM>(index)
00095 {}
00096 
00097 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00098 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, double& rJacobianDeterminant)
00099 {
00100 
00101     assert(ELEMENT_DIM <= SPACE_DIM);
00102     RefreshJacobian(rJacobian);
00103 
00104     {
00105         rJacobianDeterminant = Determinant(rJacobian);
00106         if (rJacobianDeterminant <= DBL_EPSILON)
00107         {
00108             std::stringstream string_stream;
00109             string_stream << "Jacobian determinant is non-positive: "
00110                           << "determinant = " << rJacobianDeterminant
00111                           << " for element " << this->mIndex;
00112             EXCEPTION(string_stream.str());
00113         }
00114     }
00115 }
00116 
00117 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00118 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateWeightedDirection(c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant)
00119 {
00120 
00121     if (ELEMENT_DIM >= SPACE_DIM)
00122     {
00123         assert(ELEMENT_DIM == SPACE_DIM);
00124         EXCEPTION("WeightedDirection undefined for fully dimensional element");
00125     }
00126 
00127     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00128     RefreshJacobian(jacobian);
00129 
00130     //At this point we're only dealing with subspace (ELEMENT_DIM < SPACE_DIM) elem
00131     //We assume that the rWeightedDirection vector and rJacobianDeterminant (length of vector)
00132     //are the values from a previous call.
00133 
00134     //This code is only used when ELEMENT_DIM<SPACE_DIM
00135     switch (ELEMENT_DIM)
00136     {
00137         case 0:
00138             //See specialised template for ELEMENT_DIM==0
00139             NEVER_REACHED;
00140             break;
00141         case 1:
00142             // Linear edge in a 2D plane or in 3D
00143 
00144             rWeightedDirection=matrix_column<c_matrix<double,SPACE_DIM,ELEMENT_DIM> >(jacobian, 0);
00145             break;
00146         case 2:
00147             // Surface triangle in a 3d mesh
00148             assert(SPACE_DIM == 3);
00149             rWeightedDirection(0) = -SubDeterminant(jacobian, 0, 2);
00150             rWeightedDirection(1) =  SubDeterminant(jacobian, 1, 2);
00151             rWeightedDirection(2) = -SubDeterminant(jacobian, 2, 2);
00152             break;
00153         default:
00154            ; // Not going to happen
00155     }
00156     rJacobianDeterminant = norm_2(rWeightedDirection);
00157 
00158     if (rJacobianDeterminant < DBL_EPSILON)
00159     {
00160         EXCEPTION("Jacobian determinant is zero");
00161     }
00162 }
00163 
00164 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00165 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateCentroid() const
00166 {
00167     c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM);
00168     for (unsigned i=0; i<=ELEMENT_DIM; i++)
00169     {
00170         centroid += this->mNodes[i]->rGetLocation();
00171     }
00172     return centroid/((double)(ELEMENT_DIM + 1));
00173 }
00174 
00175 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00176 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateInverseJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, double& rJacobianDeterminant, c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian)
00177 {
00178     assert(ELEMENT_DIM <= SPACE_DIM);
00179     CalculateJacobian(rJacobian, rJacobianDeterminant);
00180 
00181     // CalculateJacobian should make sure that the determinant is not close to zero (or, in fact, negative)
00182     assert(rJacobianDeterminant > 0.0);
00183     rInverseJacobian = Inverse(rJacobian);
00184 }
00185 
00186 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00187 double AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::GetVolume(double determinant) const
00188 {
00189     assert(SPACE_DIM == ELEMENT_DIM);
00190 
00191     if (this->mIsDeleted)
00192     {
00193         return 0.0;
00194     }
00195 
00196     double scale_factor = 1.0;
00197 
00198     if (ELEMENT_DIM == 2)
00199     {
00200         scale_factor = 2.0; // both the volume of the canonical triangle is 1/2
00201     }
00202     else if (ELEMENT_DIM == 3)
00203     {
00204         scale_factor = 6.0; // both the volume of the canonical triangle is 1/6
00205     }
00206     return determinant/scale_factor;
00207 }
00208 
00209 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00210 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::GetStiffnessMatrixGlobalIndices(unsigned problemDim, unsigned* pIndices) const
00211 {
00212     for (unsigned local_index=0; local_index<ELEMENT_DIM+1; local_index++)
00213     {
00214         unsigned node = this->GetNodeGlobalIndex(local_index);
00215 
00216         for (unsigned problem_index=0; problem_index<problemDim; problem_index++)
00217         {
00218             //std::cout << local_index*problemDim + problem_index << std::endl;
00219             pIndices[local_index*problemDim + problem_index] = node*problemDim + problem_index;
00220         }
00221     }
00222 }
00223 
00224 
00226 //                  Specialization for 0d elements                  //
00228 
00233 template<unsigned SPACE_DIM>
00234 class AbstractTetrahedralElement<0, SPACE_DIM> : public AbstractElement<0,SPACE_DIM>
00235 {
00236 public:
00237 
00244     AbstractTetrahedralElement(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes);
00245 
00252     AbstractTetrahedralElement(unsigned index=INDEX_IS_NOT_USED);
00253 
00257     virtual ~AbstractTetrahedralElement()
00258     {}
00259 
00263     c_vector<double, SPACE_DIM> CalculateCentroid() const;
00264 
00271     void CalculateWeightedDirection(c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant);
00272 
00281     void GetStiffnessMatrixGlobalIndices(unsigned problemDim, unsigned* pIndices) const;
00282 };
00283 
00284 #include <cassert>
00285 
00286 template<unsigned SPACE_DIM>
00287 AbstractTetrahedralElement<0, SPACE_DIM>::AbstractTetrahedralElement(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes)
00288     : AbstractElement<0, SPACE_DIM>(index, rNodes)
00289 {
00290     // Sanity checking
00291     //unsigned total_nodes = 1;
00292     assert(this->mNodes.size() == 1);
00293     assert(SPACE_DIM > 0);
00294 
00295     // This is so we know it's the first time of asking
00296     // Create Jacobian
00297     c_vector<double, SPACE_DIM> weighted_direction;
00298     double det;
00299 
00300     CalculateWeightedDirection(weighted_direction, det);
00301 
00302     // If determinant < 0 then element nodes are listed clockwise.
00303     // We want them anticlockwise.
00304     assert(det > 0.0);
00305 }
00306 
00307 template<unsigned SPACE_DIM>
00308 AbstractTetrahedralElement<0, SPACE_DIM>::AbstractTetrahedralElement(unsigned index)
00309     : AbstractElement<0, SPACE_DIM>(index)
00310 {
00311 }
00312 
00313 template<unsigned SPACE_DIM>
00314 void AbstractTetrahedralElement<0, SPACE_DIM>::CalculateWeightedDirection(
00315         c_vector<double, SPACE_DIM>& rWeightedDirection,
00316         double& rJacobianDeterminant)
00317 {
00318     assert(SPACE_DIM > 0);
00319 
00320     // End point of a line
00321     rWeightedDirection = zero_vector<double>(SPACE_DIM);
00322     rWeightedDirection(0) = 1.0;
00323 
00324     rJacobianDeterminant = 1.0;
00325 }
00326 
00327 template<unsigned SPACE_DIM>
00328 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<0, SPACE_DIM>::CalculateCentroid() const
00329 {
00330     c_vector<double, SPACE_DIM> centroid = this->mNodes[0]->rGetLocation();
00331     return centroid;
00332 }
00333 
00334 template<unsigned SPACE_DIM>
00335 void AbstractTetrahedralElement<0, SPACE_DIM>::GetStiffnessMatrixGlobalIndices(unsigned problemDim, unsigned* pIndices) const
00336 {
00337     for (unsigned local_index=0; local_index<1; local_index++)
00338     {
00339         unsigned node = this->GetNodeGlobalIndex(local_index);
00340 
00341         for (unsigned problem_index=0; problem_index<problemDim; problem_index++)
00342         {
00343             //std::cout << local_index*problemDim + problem_index << std::endl;
00344             pIndices[local_index*problemDim + problem_index] = node*problemDim + problem_index;
00345         }
00346     }
00347 }
00348 
00349 
00351 // Explicit instantiation
00353 
00354 template class AbstractTetrahedralElement<0,1>;
00355 template class AbstractTetrahedralElement<1,1>;
00356 template class AbstractTetrahedralElement<0,2>;
00357 template class AbstractTetrahedralElement<1,2>;
00358 template class AbstractTetrahedralElement<2,2>;
00359 template class AbstractTetrahedralElement<0,3>;
00360 template class AbstractTetrahedralElement<1,3>;
00361 template class AbstractTetrahedralElement<2,3>;
00362 template class AbstractTetrahedralElement<3,3>;

Generated by  doxygen 1.6.2