AbstractTetrahedralElement.cpp

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

Generated by  doxygen 1.6.2