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