AbstractTetrahedralElement.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
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 //    assert(this->mNodes.size() == total_nodes);
00064 
00065     // This is so we know it's the first time of asking
00066     // Create Jacobian
00068     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00069 
00070     if (SPACE_DIM == ELEMENT_DIM)
00071     {
00072         double det;
00073         try
00074         {
00075             CalculateJacobian(jacobian, det);
00076         }
00077         catch (Exception)
00078         {
00079             // if the Jacobian is negative the orientation of the element is probably
00080             // wrong, so swap the last two nodes around.
00081 
00082             this->mNodes[num_vectices-1] = rNodes[num_vectices-2];
00083             this->mNodes[num_vectices-2] = rNodes[num_vectices-1];
00084 
00085             CalculateJacobian(jacobian, det);
00086             // If determinant < 0 then element nodes are listed clockwise.
00087             // We want them anticlockwise.
00088             assert(det > 0.0);
00089         }
00090     }
00091     // else - don't bother working out the chirality
00092 }
00093 
00094 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00095 AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::AbstractTetrahedralElement(unsigned index)
00096     : AbstractElement<ELEMENT_DIM,SPACE_DIM>(index)
00097 {}
00098 
00099 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00100 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateJacobian(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, double& rJacobianDeterminant)
00101 {
00102 
00103     assert(ELEMENT_DIM <= SPACE_DIM);
00104     RefreshJacobian(rJacobian);
00105 
00106     {
00107         rJacobianDeterminant = Determinant(rJacobian);
00108         if (rJacobianDeterminant <= DBL_EPSILON)
00109         {
00110             std::stringstream string_stream;
00111             string_stream << "Jacobian determinant is non-positive: "
00112                           << "determinant = " << rJacobianDeterminant
00113                           << " for element " << this->mIndex;
00114             EXCEPTION(string_stream.str());
00115         }
00116     }
00117 }
00118 
00119 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00120 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateWeightedDirection(c_vector<double, SPACE_DIM>& rWeightedDirection, double& rJacobianDeterminant)
00121 {
00122  
00123     if (ELEMENT_DIM >= SPACE_DIM)
00124     {
00125         assert(ELEMENT_DIM == SPACE_DIM);
00126         EXCEPTION("WeightedDirection undefined for fully dimensional element");
00127     }
00128 
00129     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00130     RefreshJacobian(jacobian);
00131 
00132     //At this point we're only dealing with subspace (ELEMENT_DIM < SPACE_DIM) elem
00133     //We assume that the rWeightedDirection vector and rJacobianDeterminant (length of vector)
00134     //are the values from a previous call.
00135 
00136     //This code is only used when ELEMENT_DIM<SPACE_DIM
00137     switch (ELEMENT_DIM)
00138     {
00139         case 0:
00140             NEVER_REACHED; //See specialised template for ELEMENT_DIM==0
00141             break;
00142         case 1:
00143             // Linear edge in a 2D plane or in 3D
00144 
00145             rWeightedDirection=matrix_column<c_matrix<double,SPACE_DIM,ELEMENT_DIM> >(jacobian, 0);
00146             break;
00147         case 2:
00148             // Surface triangle in a 3d mesh
00149             assert(SPACE_DIM == 3);
00150             rWeightedDirection(0) = -SubDeterminant(jacobian, 0, 2);
00151             rWeightedDirection(1) =  SubDeterminant(jacobian, 1, 2);
00152             rWeightedDirection(2) = -SubDeterminant(jacobian, 2, 2);
00153             break;
00154         default:
00155            ; // Not going to happen
00156     }
00157     rJacobianDeterminant = norm_2(rWeightedDirection);
00158     
00159     if (rJacobianDeterminant < DBL_EPSILON)
00160     {
00161         EXCEPTION("Jacobian determinant is zero");
00162     }
00163 }
00164 
00165 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00166 c_vector<double, SPACE_DIM> AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::CalculateCentroid() const
00167 {
00168     c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM);
00169     for (unsigned i=0; i<=ELEMENT_DIM; i++)
00170     {
00171         centroid += this->mNodes[i]->rGetLocation();
00172     }
00173     return centroid/((double)(ELEMENT_DIM + 1));
00174 }
00175 
00176 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00177 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)
00178 {
00179     assert(ELEMENT_DIM <= SPACE_DIM);
00180     CalculateJacobian(rJacobian, rJacobianDeterminant);
00181 
00182     // CalculateJacobian should make sure that the determinant is not close to zero (or, in fact, negative)
00183     assert(rJacobianDeterminant > 0.0);
00184     rInverseJacobian = Inverse(rJacobian);
00185 }
00186 
00187 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00188 double AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::GetVolume(double determinant) const
00189 {
00190     assert(SPACE_DIM == ELEMENT_DIM);
00191 
00192     if (this->mIsDeleted)
00193     {
00194         return 0.0;
00195     }
00196 
00197     double scale_factor = 1.0;
00198 
00199     if (ELEMENT_DIM == 2)
00200     {
00201         scale_factor = 2.0; // both the volume of the canonical triangle is 1/2
00202     }
00203     else if (ELEMENT_DIM == 3)
00204     {
00205         scale_factor = 6.0; // both the volume of the canonical triangle is 1/6
00206     }
00207     return determinant/scale_factor;
00208 }
00209 
00210 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00211 void AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>::GetStiffnessMatrixGlobalIndices(unsigned problemDim, unsigned* pIndices) const
00212 {
00213     for (unsigned local_index=0; local_index<ELEMENT_DIM+1; local_index++)
00214     {
00215         unsigned node = this->GetNodeGlobalIndex(local_index);
00216 
00217         for (unsigned problem_index=0; problem_index<problemDim; problem_index++)
00218         {
00219             //std::cout << local_index*problemDim + problem_index << std::endl;
00220             pIndices[local_index*problemDim + problem_index] = node*problemDim + problem_index;
00221         }
00222     }
00223 }
00224 
00225 
00227 // Explicit instantiation
00229 
00230 template class AbstractTetrahedralElement<0,1>;
00231 template class AbstractTetrahedralElement<1,1>;
00232 template class AbstractTetrahedralElement<0,2>;
00233 template class AbstractTetrahedralElement<1,2>;
00234 template class AbstractTetrahedralElement<2,2>;
00235 template class AbstractTetrahedralElement<0,3>;
00236 template class AbstractTetrahedralElement<1,3>;
00237 template class AbstractTetrahedralElement<2,3>;
00238 template class AbstractTetrahedralElement<3,3>;

Generated on Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5