AbstractTetrahedralElement.cpp

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