Element.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 
00030 
00031 #include "Element.hpp"
00032 
00033 #include <cassert>
00034 
00035 
00037 // Implementation
00039 
00040 
00041 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00042 Element<ELEMENT_DIM, SPACE_DIM>::Element(unsigned index, std::vector<Node<SPACE_DIM>*> nodes)
00043     : AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>(index, nodes)
00044 {
00045     RegisterWithNodes();
00046 }
00047 
00048 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00049 Element<ELEMENT_DIM, SPACE_DIM>::Element(const Element& rElement, const unsigned index)
00050 {
00051     *this = rElement;
00052     this->mIndex = index;
00053 
00054     RegisterWithNodes();
00055 }
00056 
00057 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00058 void Element<ELEMENT_DIM, SPACE_DIM>::RegisterWithNodes()
00059 {
00060     for (unsigned i=0; i<this->mNodes.size(); i++)
00061     {
00062         this->mNodes[i]->AddElement(this->mIndex);
00063     }
00064 }
00065 
00066 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00067 void Element<ELEMENT_DIM, SPACE_DIM>::MarkAsDeleted()
00068 {
00069     this->mIsDeleted = true;
00070     // Update nodes in this element so they know they are not contained by us
00071     for (unsigned i=0; i<this->GetNumNodes(); i++)
00072     {
00073         this->mNodes[i]->RemoveElement(this->mIndex);
00074     }
00075 }
00076 
00081 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00082 void Element<ELEMENT_DIM, SPACE_DIM>::UpdateNode(const unsigned& rIndex, Node<SPACE_DIM>* pNode)
00083 {
00084     assert(rIndex < this->mNodes.size());
00085 
00086     // Remove it from the node at this location
00087     this->mNodes[rIndex]->RemoveElement(this->mIndex);
00088 
00089     // Update the node at this location
00090     this->mNodes[rIndex] = pNode;
00091 
00092     // Add element to this node
00093     this->mNodes[rIndex]->AddElement(this->mIndex);
00094 }
00095 
00096 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00097 void Element<ELEMENT_DIM, SPACE_DIM>::ResetIndex(unsigned index)
00098 {
00099     //std::cout << "ResetIndex - removing nodes.\n" << std::flush;
00100     for (unsigned i=0; i<this->GetNumNodes(); i++)
00101     {
00102        //std::cout << "Node " << this->mNodes[i]->GetIndex() << " element "<< this->mIndex << std::flush;
00103        this->mNodes[i]->RemoveElement(this->mIndex);
00104     }
00105     //std::cout << "\nResetIndex - done.\n" << std::flush;
00106     this->mIndex=index;
00107     RegisterWithNodes();
00108 }
00109 
00110 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00111 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)
00112 {
00113     /*Assuming that x0,y0.. is at the origin then we need to solve
00114      *
00115      * ( 2x1 2y1 2z1  ) (x)    (x1^2+y1^2+z1^2)
00116      * ( 2x2 2y2 2z2  ) (y)    (x2^2+y2^2+z2^2)
00117      * ( 2x3 2y3 2z3  ) (z)    (x3^2+y3^2+z3^2)
00118      * where (x,y,z) is the circumcentre
00119      *
00120      */
00121 
00122     assert(ELEMENT_DIM == SPACE_DIM);
00123     c_vector<double, ELEMENT_DIM> rhs;
00124 
00125     for (unsigned j=0; j<ELEMENT_DIM; j++)
00126     {
00127         double squared_location=0.0;
00128         for (unsigned i=0; i<SPACE_DIM; i++)
00129         {
00130             //mJacobian(i,j) is the i-th component of j-th vertex (relative to vertex 0)
00131             squared_location += rJacobian(i,j)*rJacobian(i,j);
00132         }
00133         rhs[j]=squared_location/2.0;
00134     }
00135 
00136     c_vector<double, SPACE_DIM> centre;
00137     centre = prod(rhs, rInverseJacobian);
00138     c_vector<double, SPACE_DIM+1> circum;
00139     double squared_radius = 0.0;
00140     for (unsigned i=0; i<SPACE_DIM; i++)
00141     {
00142         circum[i] = centre[i] + this->GetNodeLocation(0,i);
00143         squared_radius += centre[i]*centre[i];
00144     }
00145     circum[SPACE_DIM] = squared_radius;
00146 
00147     return circum;
00148 }
00149 
00155 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00156 double Element<ELEMENT_DIM, SPACE_DIM>::CalculateQuality()
00157 {
00158     assert(SPACE_DIM == ELEMENT_DIM);
00159     if (SPACE_DIM == 1)
00160     {
00161         return 1.0;
00162     }
00163 
00164     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00165     c_matrix<double, ELEMENT_DIM, SPACE_DIM> jacobian_inverse;
00166     double jacobian_determinant;
00167 
00168     CalculateInverseJacobian(jacobian, jacobian_determinant, jacobian_inverse);
00169 
00170     c_vector<double, SPACE_DIM+1> circum=CalculateCircumsphere(jacobian, jacobian_inverse);
00171     if (SPACE_DIM == 2)
00172     {
00173         /* Want Q=(Area_Tri / Area_Cir) / (Area_Equilateral_Tri / Area_Equilateral_Cir)
00174          * Area_Tri = |Jacobian| /2
00175          * Area_Cir = Pi * r^2
00176          * Area_Eq_Tri = (3*sqrt(3)/4)*R^2
00177          * Area_Eq_Tri = Pi * R^2
00178          * Q= (2*|Jacobian|)/3*sqrt(3)*r^2)
00179          */
00180         return 2.0*jacobian_determinant/(3.0*sqrt(3)*circum[SPACE_DIM]);
00181     }
00182     assert(SPACE_DIM == 3);
00183     /* Want Q=(Vol_Tet / Vol_CirS) / (Vol_Plat_Tet / Vol_Plat_CirS)
00184       *  Vol_Tet  = |Jacobian| /6
00185       *  Vol_CirS = 4*Pi*r^3/3
00186       *  Vol_Plat_Tet  = 8*sqrt(3)*R^3/27
00187       *  Vol_Plat_CirS = 4*Pi*R^3/3
00188      * Q= 3*sqrt(3)*|Jacobian|/ (16*r^3)
00189       */
00190 
00191     return (3.0*sqrt(3.0)*jacobian_determinant)
00192            /(16.0*circum[SPACE_DIM]*sqrt(circum[SPACE_DIM]));
00193 }
00194 
00195 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00196 c_vector<double, SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateInterpolationWeights(ChastePoint<SPACE_DIM> testPoint)
00197 {
00198     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00199     assert(ELEMENT_DIM == SPACE_DIM);
00200 
00201     c_vector<double, SPACE_DIM+1> weights;
00202 
00203     c_vector<double, SPACE_DIM> psi=CalculatePsi(testPoint);
00204 
00205     //Copy 3 weights and compute the fourth weight
00206     weights[0]=1.0;
00207     for (unsigned i=1; i<=SPACE_DIM; i++)
00208     {
00209         weights[0] -= psi[i-1];
00210         weights[i] = psi[i-1];
00211     }
00212     return weights;
00213 }
00214 
00220 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00221 c_vector<double, SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateInterpolationWeightsWithProjection(ChastePoint<SPACE_DIM> testPoint)
00222 {
00223     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00224     assert(ELEMENT_DIM == SPACE_DIM);
00225 
00226     c_vector<double, SPACE_DIM+1> weights = CalculateInterpolationWeights(testPoint);
00227 
00228     // Check for negative weights and set them to zero.
00229     bool negative_weight = false;
00230 
00231     for (unsigned i=0; i<=SPACE_DIM; i++)
00232     {
00233         if (weights[i] < 0.0)
00234         {
00235             weights[i] = 0.0;
00236 
00237             negative_weight = true;
00238         }
00239     }
00240 
00241     if (negative_weight == false)
00242     {
00243         // If there are no negative weights, there is nothing to do.
00244         return weights;
00245     }
00246 
00247     // Renormalise so that all weights add to 1.0.
00248 
00249     // 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
00250     double sum = norm_1 (weights);
00251 
00252     //l1-norm ought to be above 1 (because we scrubbed negative weights)
00253     //However, if we scrubbed weights that were the size of the machine precision then we might be close to one (even less than 1).
00254     assert( sum + DBL_EPSILON >= 1.0);
00255 
00256     //We might skip this division when sum ~= 1
00257     weights = weights/sum;
00258 
00259     return weights;
00260 }
00261 
00262 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00263 c_vector<double, SPACE_DIM> Element<ELEMENT_DIM, SPACE_DIM>::CalculatePsi(ChastePoint<SPACE_DIM> testPoint)
00264 {
00265     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00266     assert(ELEMENT_DIM == SPACE_DIM);
00267 
00268     //Find the location with respect to node 0
00269     c_vector<double, SPACE_DIM> test_location=testPoint.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     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(ChastePoint<SPACE_DIM> testPoint, 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(testPoint);
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 Tue Aug 4 16:10:22 2009 for Chaste by  doxygen 1.5.5