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 
00035 // Implementation
00037 
00038 
00039 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00040 Element<ELEMENT_DIM, SPACE_DIM>::Element(unsigned index, std::vector<Node<SPACE_DIM>*> nodes)
00041     : AbstractTetrahedralElement<ELEMENT_DIM, SPACE_DIM>(index, nodes)
00042 {
00043     RegisterWithNodes();
00044 }
00045 
00046 
00053 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00054 Element<ELEMENT_DIM, SPACE_DIM>::Element(const Element &element, const unsigned index)
00055 {
00056     *this = element; 
00057     this->mIndex=index;
00058 
00059     RegisterWithNodes();
00060 }
00061 
00062 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00063 void Element<ELEMENT_DIM, SPACE_DIM>::RegisterWithNodes()
00064 {
00065     for (unsigned i=0; i<this->mNodes.size(); i++)
00066     {
00067         this->mNodes[i]->AddElement(this->mIndex);
00068     }
00069 }
00070 
00071 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00072 void Element<ELEMENT_DIM, SPACE_DIM>::MarkAsDeleted()
00073 {
00074     this->mIsDeleted = true;
00075 //    this->mJacobianDeterminant = 0.0;
00076     // Update nodes in this element so they know they are not contained by us
00077     for (unsigned i=0; i<this->GetNumNodes(); i++)
00078     {
00079         this->mNodes[i]->RemoveElement(this->mIndex);
00080     }
00081 }
00082 
00087 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00088 void Element<ELEMENT_DIM, SPACE_DIM>::UpdateNode(const unsigned& rIndex, Node<SPACE_DIM>* pNode)
00089 {
00090     assert(rIndex < this->mNodes.size());
00091 
00092     // Remove it from the node at this location
00093     this->mNodes[rIndex]->RemoveElement(this->mIndex);
00094 
00095     // Update the node at this location
00096     this->mNodes[rIndex] = pNode;
00097 
00098     // Add element to this node
00099     this->mNodes[rIndex]->AddElement(this->mIndex);
00100 }
00101 
00102 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00103 void Element<ELEMENT_DIM, SPACE_DIM>::ResetIndex(unsigned index)
00104 {
00105     //std::cout << "ResetIndex - removing nodes.\n" << std::flush;
00106     for (unsigned i=0; i<this->GetNumNodes(); i++)
00107     {
00108        //std::cout << "Node " << this->mNodes[i]->GetIndex() << " element "<< this->mIndex << std::flush;
00109        this->mNodes[i]->RemoveElement(this->mIndex);
00110     }
00111     //std::cout << "\nResetIndex - done.\n" << std::flush;
00112     this->mIndex=index;
00113     RegisterWithNodes();
00114 }
00115 
00121 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00122 c_vector<double,SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateCircumsphere()
00123 {
00124     /*Assuming that x0,y0.. is at the origin then we need to solve
00125      *
00126      * ( 2x1 2y1 2z1  ) (x)    (x1^2+y1^2+z1^2)
00127      * ( 2x2 2y2 2z2  ) (y)    (x2^2+y2^2+z2^2)
00128      * ( 2x3 2y3 2z3  ) (z)    (x3^2+y3^2+z3^2)
00129      * where (x,y,z) is the circumcentre
00130      *
00131      */
00132     assert(ELEMENT_DIM == SPACE_DIM);
00133     c_vector <double, ELEMENT_DIM> rhs;
00134 
00135     c_matrix<double, SPACE_DIM, SPACE_DIM> jacobian;
00136     c_matrix<double, SPACE_DIM, SPACE_DIM> inverse_jacobian;
00137     double jacobian_determinant;
00138     
00139     CalculateInverseJacobian(jacobian, jacobian_determinant, inverse_jacobian);
00140 
00141     for (unsigned j=0; j<ELEMENT_DIM; j++)
00142     {
00143         double squared_location=0.0;
00144         for (unsigned i=0; i<SPACE_DIM; i++)
00145         {
00146             //mJacobian(i,j) is the i-th component of j-th vertex (relative to vertex 0)
00147             squared_location += jacobian(i,j)*jacobian(i,j);
00148         }
00149         rhs[j]=squared_location/2.0;
00150     }
00151 
00152     c_vector <double, SPACE_DIM> centre;
00153     centre = prod(rhs, inverse_jacobian);
00154     c_vector <double, SPACE_DIM+1> circum;
00155     double squared_radius=0.0;
00156     for (unsigned i=0; i<SPACE_DIM; i++)
00157     {
00158         circum[i] = centre[i] + this->GetNodeLocation(0,i);
00159         squared_radius += centre[i]*centre[i];
00160     }
00161     circum[SPACE_DIM] = squared_radius;
00162 
00163     return circum;
00164 
00165 }
00166 
00167 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00168 c_vector<double,SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateCircumsphere(c_matrix<double, SPACE_DIM, SPACE_DIM>& rJacobian, c_matrix<double, SPACE_DIM, SPACE_DIM>& rInverseJacobian)
00169 {
00170     /*Assuming that x0,y0.. is at the origin then we need to solve
00171      *
00172      * ( 2x1 2y1 2z1  ) (x)    (x1^2+y1^2+z1^2)
00173      * ( 2x2 2y2 2z2  ) (y)    (x2^2+y2^2+z2^2)
00174      * ( 2x3 2y3 2z3  ) (z)    (x3^2+y3^2+z3^2)
00175      * where (x,y,z) is the circumcentre
00176      *
00177      */
00178      
00179     assert(ELEMENT_DIM == SPACE_DIM);
00180     c_vector <double, ELEMENT_DIM> rhs;
00181 
00182     for (unsigned j=0; j<ELEMENT_DIM; j++)
00183     {
00184         double squared_location=0.0;
00185         for (unsigned i=0; i<SPACE_DIM; i++)
00186         {
00187             //mJacobian(i,j) is the i-th component of j-th vertex (relative to vertex 0)
00188             squared_location += rJacobian(i,j)*rJacobian(i,j);
00189         }
00190         rhs[j]=squared_location/2.0;
00191     }
00192 
00193     c_vector <double, SPACE_DIM> centre;
00194     centre = prod(rhs, rInverseJacobian);
00195     c_vector <double, SPACE_DIM+1> circum;
00196     double squared_radius = 0.0;
00197     for (unsigned i=0; i<SPACE_DIM; i++)
00198     {
00199         circum[i] = centre[i] + this->GetNodeLocation(0,i);
00200         squared_radius += centre[i]*centre[i];
00201     }
00202     circum[SPACE_DIM] = squared_radius;
00203 
00204     return circum;
00205 }
00206 
00207 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00208 double Element<ELEMENT_DIM, SPACE_DIM>::CalculateCircumsphereVolume()
00209 {
00210     c_vector<double, SPACE_DIM+1> circum=CalculateCircumsphere();
00211     if (SPACE_DIM == 1)
00212     {
00213         return 2.0*sqrt(circum[SPACE_DIM]); //2*r
00214     }
00215     else if (SPACE_DIM == 2)
00216     {
00217         return M_PI*circum[SPACE_DIM]; //Pi*r^2
00218     }
00219     assert(SPACE_DIM == 3);
00220     return 4.0*M_PI*circum[SPACE_DIM]*sqrt(circum[SPACE_DIM])/3.0; //4*Pi*r^3/3
00221 }
00222 
00228 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00229 double Element<ELEMENT_DIM, SPACE_DIM>::CalculateQuality()
00230 {
00231     assert(SPACE_DIM == ELEMENT_DIM);
00232     if (SPACE_DIM == 1)
00233     {
00234         return 1.0;
00235     }
00236     
00237     c_matrix<double, SPACE_DIM, SPACE_DIM> jacobian;
00238     double jacobian_determinant;
00239     
00240     CalculateJacobian(jacobian, jacobian_determinant);    
00241 
00242     c_vector<double, SPACE_DIM+1> circum=CalculateCircumsphere();
00243     if (SPACE_DIM == 2)
00244     {
00245         /* Want Q=(Area_Tri / Area_Cir) / (Area_Equilateral_Tri / Area_Equilateral_Cir)
00246          * Area_Tri = |Jacobian| /2
00247          * Area_Cir = Pi * r^2
00248          * Area_Eq_Tri = (3*sqrt(3)/4)*R^2
00249          * Area_Eq_Tri = Pi * R^2
00250          * Q= (2*|Jacobian|)/ (    bool CalculateVoronoiElement(c_vector <double, 3> first_node, c_vector <double, 3> second_node)
00251         {
00252         double x_diff_sqr = ((first_node[0] - second_node[0])*(first_node[0] - second_node[0]));
00253         double y_diff_sqr = ((first_node[1] - second_node[1])*(first_node[1] - second_node[1]));
00254 
00255         return ((x_diff_sqr + y_diff_sqr) > first_node[2]);
00256         }3*sqrt(3)*r^2)
00257          */
00258         return 2.0*jacobian_determinant/(3.0*sqrt(3)*circum[SPACE_DIM]);
00259     }
00260     assert(SPACE_DIM == 3);
00261     /* Want Q=(Vol_Tet / Vol_CirS) / (Vol_Plat_Tet / Vol_Plat_CirS)
00262       *  Vol_Tet  = |Jacobian| /6
00263       *  Vol_CirS = 4*Pi*r^3/3
00264       *  Vol_Plat_Tet  = 8*sqrt(3)*R^3/27
00265       *  Vol_Plat_CirS = 4*Pi*R^3/3
00266      * Q= 3*sqrt(3)*|Jacobian|/ (16*r^3)
00267       */
00268 
00269     return (3.0*sqrt(3.0)*jacobian_determinant)
00270            /(16.0*circum[SPACE_DIM]*sqrt(circum[SPACE_DIM]));
00271 }
00272 
00273 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00274 c_vector<double, SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateInterpolationWeights(ChastePoint<SPACE_DIM> testPoint)
00275 {
00276     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00277     assert(ELEMENT_DIM == SPACE_DIM);
00278 
00279     c_vector<double, SPACE_DIM+1> weights;
00280 
00281     c_vector<double, SPACE_DIM> psi=CalculatePsi(testPoint);
00282 
00283     //Copy 3 weights and compute the fourth weight
00284     weights[0]=1.0;
00285     for (unsigned i=1; i<=SPACE_DIM; i++)
00286     {
00287         weights[0] -= psi[i-1];
00288         weights[i] = psi[i-1];
00289     }
00290     return weights;
00291 }
00292 
00298 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00299 c_vector<double, SPACE_DIM+1> Element<ELEMENT_DIM, SPACE_DIM>::CalculateInterpolationWeightsWithProjection(ChastePoint<SPACE_DIM> testPoint)
00300 {
00301     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00302     assert(ELEMENT_DIM == SPACE_DIM);
00303 
00304     c_vector<double, SPACE_DIM+1> weights = CalculateInterpolationWeights(testPoint);
00305 
00306     // Check for negative weights and set them to zero.
00307     bool negative_weight = false;
00308     
00309     for(unsigned i=0;i<=SPACE_DIM;i++)
00310     {
00311         if(weights[i] < 0.0)
00312         {
00313             weights[i] = 0.0;
00314             
00315             negative_weight = true;
00316         }   
00317     }
00318     
00319     if(negative_weight == false)
00320     {
00321         // If there are no negative weights, there is nothing to do.
00322         return weights;   
00323     }
00324     
00325     // Renormalise so that all weights add to 1.0.
00326     
00327     // 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 
00328     double sum = norm_1 (weights);
00329     
00330     assert(sum >= 1.0);
00331     
00332     weights = weights/sum;
00333     
00334     return weights;
00335     
00336 }
00337 
00338 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00339 c_vector<double, SPACE_DIM> Element<ELEMENT_DIM, SPACE_DIM>::CalculatePsi(ChastePoint<SPACE_DIM> testPoint)
00340 {
00341     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00342     assert(ELEMENT_DIM == SPACE_DIM);
00343 
00344     //Find the location with respect to node 0
00345     c_vector<double, SPACE_DIM> test_location=testPoint.rGetLocation()-this->GetNodeLocation(0);
00346 
00347     //Multiply by inverse Jacobian
00348     c_matrix<double, SPACE_DIM, SPACE_DIM> jacobian;
00349     c_matrix<double, SPACE_DIM, SPACE_DIM> inverse_jacobian;
00350     double jacobian_determinant;
00351     
00352     CalculateInverseJacobian(jacobian, jacobian_determinant, inverse_jacobian);
00353     
00354     return prod(inverse_jacobian, test_location);
00355 }
00356 
00357 
00358 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00359 bool Element<ELEMENT_DIM, SPACE_DIM>::IncludesPoint(ChastePoint<SPACE_DIM> testPoint, bool strict)
00360 {
00361     //Can only test if it's a tetrahedal mesh in 3d, triangles in 2d...
00362     assert(ELEMENT_DIM == SPACE_DIM);
00363 
00364     c_vector<double, SPACE_DIM+1> weights=CalculateInterpolationWeights(testPoint);
00365 
00366     //If the point is in the simplex then all the weights should be positive
00367 
00368     for (unsigned i=0;i<=SPACE_DIM;i++)
00369     {
00370         if (strict)
00371         {
00372             //Points can't be close to a face
00373             if (weights[i] <= 2*DBL_EPSILON)
00374             {
00375                 return false;
00376             }
00377         }
00378         else
00379         {
00380             //Allow point to be close to a face
00381             if (weights[i] < -2*DBL_EPSILON)
00382             {
00383                 return false;
00384             }
00385         }
00386     }
00387     return true;
00388 }
00389 
00390 template class Element<1,1>;
00391 template class Element<1,2>;
00392 template class Element<2,2>;
00393 template class Element<2,3>;
00394 template class Element<3,3>;

Generated on Wed Mar 18 12:51:52 2009 for Chaste by  doxygen 1.5.5