Element.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 "Element.hpp"
00037 
00038 #include <cfloat>
00039 #include <cassert>
00040 
00042 // Implementation
00044 
00045 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00046 Element<ELEMENT_DIM, SPACE_DIM>::Element(unsigned index, const std::vector<Node<SPACE_DIM>*>& rNodes, bool registerWithNodes)
00047     : AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>(index, rNodes)
00048 {
00049     if (registerWithNodes)
00050     {
00051         RegisterWithNodes();
00052     }
00053 }
00054 
00055 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00056 Element<ELEMENT_DIM, SPACE_DIM>::Element(const Element& rElement, const unsigned index)
00057 {
00058     *this = rElement;
00059     this->mIndex = index;
00060 
00061     RegisterWithNodes();
00062 }
00063 
00064 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00065 void Element<ELEMENT_DIM, SPACE_DIM>::RegisterWithNodes()
00066 {
00067     for (unsigned i=0; i<this->mNodes.size(); i++)
00068     {
00069         this->mNodes[i]->AddElement(this->mIndex);
00070     }
00071 }
00072 
00073 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00074 void Element<ELEMENT_DIM, SPACE_DIM>::MarkAsDeleted()
00075 {
00076     this->mIsDeleted = true;
00077     // Update nodes in this element so they know they are not contained by us
00078     for (unsigned i=0; i<this->GetNumNodes(); i++)
00079     {
00080         this->mNodes[i]->RemoveElement(this->mIndex);
00081     }
00082 }
00083 
00088 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00089 void Element<ELEMENT_DIM, SPACE_DIM>::UpdateNode(const unsigned& rIndex, Node<SPACE_DIM>* pNode)
00090 {
00091     assert(rIndex < this->mNodes.size());
00092 
00093     // Remove it from the node at this location
00094     this->mNodes[rIndex]->RemoveElement(this->mIndex);
00095 
00096     // Update the node at this location
00097     this->mNodes[rIndex] = pNode;
00098 
00099     // Add element to this node
00100     this->mNodes[rIndex]->AddElement(this->mIndex);
00101 }
00102 
00103 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00104 void Element<ELEMENT_DIM, SPACE_DIM>::ResetIndex(unsigned index)
00105 {
00106     //std::cout << "ResetIndex - removing nodes.\n" << std::flush;
00107     for (unsigned i=0; i<this->GetNumNodes(); i++)
00108     {
00109        //std::cout << "Node " << this->mNodes[i]->GetIndex() << " element "<< this->mIndex << std::flush;
00110        this->mNodes[i]->RemoveElement(this->mIndex);
00111     }
00112     //std::cout << "\nResetIndex - done.\n" << std::flush;
00113     this->mIndex=index;
00114     RegisterWithNodes();
00115 }
00116 
00117 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00118 c_vector<double,SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateCircumsphere(c_matrix<double, SPACE_DIM, ELEMENT_DIM>& rJacobian, c_matrix<double, ELEMENT_DIM, SPACE_DIM>& rInverseJacobian)
00119 {
00120     /*Assuming that x0,y0.. is at the origin then we need to solve
00121      *
00122      * ( 2x1 2y1 2z1  ) (x)    (x1^2+y1^2+z1^2)
00123      * ( 2x2 2y2 2z2  ) (y)    (x2^2+y2^2+z2^2)
00124      * ( 2x3 2y3 2z3  ) (z)    (x3^2+y3^2+z3^2)
00125      * where (x,y,z) is the circumcentre
00126      *
00127      */
00128 
00129     assert(ELEMENT_DIM == SPACE_DIM);
00130     c_vector<double, ELEMENT_DIM> rhs;
00131 
00132     for (unsigned j=0; j<ELEMENT_DIM; j++)
00133     {
00134         double squared_location=0.0;
00135         for (unsigned i=0; i<SPACE_DIM; i++)
00136         {
00137             //mJacobian(i,j) is the i-th component of j-th vertex (relative to vertex 0)
00138             squared_location += rJacobian(i,j)*rJacobian(i,j);
00139         }
00140         rhs[j]=squared_location/2.0;
00141     }
00142 
00143     c_vector<double, SPACE_DIM> centre;
00144     centre = prod(rhs, rInverseJacobian);
00145     c_vector<double, SPACE_DIM+1> circum;
00146     double squared_radius = 0.0;
00147     for (unsigned i=0; i<SPACE_DIM; i++)
00148     {
00149         circum[i] = centre[i] + this->GetNodeLocation(0,i);
00150         squared_radius += centre[i]*centre[i];
00151     }
00152     circum[SPACE_DIM] = squared_radius;
00153 
00154     return circum;
00155 }
00156 
00162 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00163 double Element<ELEMENT_DIM, SPACE_DIM>::CalculateQuality()
00164 {
00165     assert(SPACE_DIM == ELEMENT_DIM);
00166     if (SPACE_DIM == 1)
00167     {
00168         return 1.0;
00169     }
00170 
00171     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00172     c_matrix<double, ELEMENT_DIM, SPACE_DIM> jacobian_inverse;
00173     double jacobian_determinant;
00174 
00175     this->CalculateInverseJacobian(jacobian, jacobian_determinant, jacobian_inverse);
00176 
00177     c_vector<double, SPACE_DIM+1> circum=CalculateCircumsphere(jacobian, jacobian_inverse);
00178     if (SPACE_DIM == 2)
00179     {
00180         /* Want Q=(Area_Tri / Area_Cir) / (Area_Equilateral_Tri / Area_Equilateral_Cir)
00181          * Area_Tri = |Jacobian| /2
00182          * Area_Cir = Pi * r^2
00183          * Area_Eq_Tri = (3*sqrt(3.0)/4)*R^2
00184          * Area_Eq_Tri = Pi * R^2
00185          * Q= (2*|Jacobian|)/3*sqrt(3.0)*r^2)
00186          */
00187         return 2.0*jacobian_determinant/(3.0*sqrt(3.0)*circum[SPACE_DIM]);
00188     }
00189     assert(SPACE_DIM == 3);
00190     /* Want Q=(Vol_Tet / Vol_CirS) / (Vol_Plat_Tet / Vol_Plat_CirS)
00191       *  Vol_Tet  = |Jacobian| /6
00192       *  Vol_CirS = 4*Pi*r^3/3
00193       *  Vol_Plat_Tet  = 8*sqrt(3.0)*R^3/27
00194       *  Vol_Plat_CirS = 4*Pi*R^3/3
00195      * Q= 3*sqrt(3.0)*|Jacobian|/ (16*r^3)
00196       */
00197 
00198     return (3.0*sqrt(3.0)*jacobian_determinant)
00199            /(16.0*circum[SPACE_DIM]*sqrt(circum[SPACE_DIM]));
00200 }
00201 
00202 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00203 c_vector <double, 2> Element<ELEMENT_DIM, SPACE_DIM>::CalculateMinMaxEdgeLengths()
00204 {
00205     c_vector <double, 2> min_max;
00206     min_max[0] = DBL_MAX; //Min initialised to very large
00207     min_max[1] = 0.0;     //Max initialised to zero
00208     for (unsigned i=0; i<=ELEMENT_DIM; i++)
00209     {
00210         c_vector<double, SPACE_DIM> loc_i = this->GetNodeLocation(i);
00211         for (unsigned j=i+1; j<=ELEMENT_DIM; j++)
00212         {
00213             double length = norm_2(this->GetNodeLocation(j) - loc_i);
00214             if (length < min_max[0])
00215             {
00216                 min_max[0] = length;
00217             }
00218             if (length > min_max[1])
00219             {
00220                 min_max[1] = length;
00221             }
00222         }
00223     }
00224     return min_max;
00225 }
00226 
00227 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00228 c_vector<double, SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateInterpolationWeights(const ChastePoint<SPACE_DIM>& rTestPoint)
00229 {
00230     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00231     assert(ELEMENT_DIM == SPACE_DIM);
00232 
00233     c_vector<double, SPACE_DIM+1> weights;
00234 
00235     c_vector<double, SPACE_DIM> xi=CalculateXi(rTestPoint);
00236 
00237     //Copy 3 weights and compute the fourth weight
00238     weights[0]=1.0;
00239     for (unsigned i=1; i<=SPACE_DIM; i++)
00240     {
00241         weights[0] -= xi[i-1];
00242         weights[i] = xi[i-1];
00243     }
00244     return weights;
00245 }
00246 
00247 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00248 c_vector<double, SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateInterpolationWeightsWithProjection(const ChastePoint<SPACE_DIM>& rTestPoint)
00249 {
00250     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00251     assert(ELEMENT_DIM == SPACE_DIM);
00252 
00253     c_vector<double, SPACE_DIM+1> weights = CalculateInterpolationWeights(rTestPoint);
00254 
00255     // Check for negative weights and set them to zero.
00256     bool negative_weight = false;
00257 
00258     for (unsigned i=0; i<=SPACE_DIM; i++)
00259     {
00260         if (weights[i] < 0.0)
00261         {
00262             weights[i] = 0.0;
00263 
00264             negative_weight = true;
00265         }
00266     }
00267 
00268     if (negative_weight == false)
00269     {
00270         // If there are no negative weights, there is nothing to do.
00271         return weights;
00272     }
00273 
00274     // Renormalise so that all weights add to 1.0.
00275 
00276     // Note that all elements of weights are now non-negative and so the l1-norm (sum of magnitudes) is equivalent to the sum of the elements of the vector
00277     double sum = norm_1 (weights);
00278 
00279     //l1-norm ought to be above 1 (because we scrubbed negative weights)
00280     //However, if we scrubbed weights that were the size of the machine precision then we might be close to one (even less than 1).
00281     assert( sum + DBL_EPSILON >= 1.0);
00282 
00283     //We might skip this division when sum ~= 1
00284     weights = weights/sum;
00285 
00286     return weights;
00287 }
00288 
00289 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00290 c_vector<double, SPACE_DIM> Element<ELEMENT_DIM, SPACE_DIM>::CalculateXi(const ChastePoint<SPACE_DIM>& rTestPoint)
00291 {
00292     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00293     assert(ELEMENT_DIM == SPACE_DIM);
00294 
00295     // Find the location with respect to node 0
00298     c_vector<double, SPACE_DIM> test_location=rTestPoint.rGetLocation()-this->GetNodeLocation(0);
00299 
00300     //Multiply by inverse Jacobian
00301     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00302     c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
00303     double jacobian_determinant;
00304 
00306     this->CalculateInverseJacobian(jacobian, jacobian_determinant, inverse_jacobian);
00307 
00308     return prod(inverse_jacobian, test_location);
00309 }
00310 
00311 
00312 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00313 bool Element<ELEMENT_DIM, SPACE_DIM>::IncludesPoint(const ChastePoint<SPACE_DIM>& rTestPoint, bool strict)
00314 {
00315     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00316     assert(ELEMENT_DIM == SPACE_DIM);
00317 
00318     c_vector<double, SPACE_DIM+1> weights=CalculateInterpolationWeights(rTestPoint);
00319 
00320     //If the point is in the simplex then all the weights should be positive
00321 
00322     for (unsigned i=0; i<=SPACE_DIM; i++)
00323     {
00324         if (strict)
00325         {
00326             //Points can't be close to a face
00327             if (weights[i] <= 2*DBL_EPSILON)
00328             {
00329                 return false;
00330             }
00331         }
00332         else
00333         {
00334             //Allow point to be close to a face
00335             if (weights[i] < -2*DBL_EPSILON)
00336             {
00337                 return false;
00338             }
00339         }
00340     }
00341     return true;
00342 }
00343 
00345 // Explicit instantiation
00347 
00348 template class Element<1,1>;
00349 template class Element<1,2>;
00350 template class Element<1,3>;
00351 template class Element<2,2>;
00352 template class Element<2,3>;
00353 template class Element<3,3>;

Generated by  doxygen 1.6.2