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