VertexMesh.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
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 "VertexMesh.hpp"
00030 #include "RandomNumberGenerator.hpp"
00031 #include "UblasCustomFunctions.hpp"
00032 #include <list>
00033 
00038 bool IndexAngleComparison(const std::pair<unsigned, double> lhs, const std::pair<unsigned, double> rhs)
00039 {
00040     return lhs.second < rhs.second;
00041 }
00042 
00043 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00044 VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexMesh(std::vector<Node<SPACE_DIM>*> nodes,
00045                                                std::vector<VertexElement<ELEMENT_DIM,SPACE_DIM>*> vertexElements)
00046     : mpDelaunayMesh(NULL)
00047 {
00048 
00049     // Reset member variables and clear mNodes and mElements
00050     Clear();
00051 
00052     // Populate mNodes and mElements
00053     for (unsigned node_index=0; node_index<nodes.size(); node_index++)
00054     {
00055         Node<SPACE_DIM>* p_temp_node = nodes[node_index];
00056         this->mNodes.push_back(p_temp_node);
00057     }
00058     for (unsigned elem_index=0; elem_index<vertexElements.size(); elem_index++)
00059     {
00060         VertexElement<ELEMENT_DIM, SPACE_DIM>* p_temp_vertex_element = vertexElements[elem_index];
00061         mElements.push_back(p_temp_vertex_element);
00062     }
00063 
00064     // In 3D, populate mFaces
00065     if (SPACE_DIM == 3)
00066     {
00067         // Use a std::set to keep track of which faces have been added to mFaces
00068         std::set<unsigned> faces_counted;
00069 
00070         // Loop over mElements
00071         for (unsigned elem_index=0; elem_index<mElements.size(); elem_index++)
00072         {
00073             // Loop over faces of this element
00074             for (unsigned face_index=0; face_index<mElements[elem_index]->GetNumFaces(); face_index++)
00075             {
00076                 VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_face = mElements[elem_index]->GetFace(face_index);
00077                 unsigned global_index = p_face->GetIndex();
00078 
00079                 // If this face is not already contained in mFaces, add it, and update faces_counted
00080                 if (faces_counted.find(global_index) == faces_counted.end())
00081                 {
00082                     mFaces.push_back(p_face);
00083                     faces_counted.insert(global_index);
00084                 }
00085             }
00086         }
00087     }
00088 
00089     // Register elements with nodes
00090     for (unsigned index=0; index<mElements.size(); index++)
00091     {
00092         VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = mElements[index];
00093 
00094         unsigned element_index = p_element->GetIndex();
00095         unsigned num_nodes_in_element = p_element->GetNumNodes();
00096 
00097         for (unsigned node_index=0; node_index<num_nodes_in_element; node_index++)
00098         {
00099             p_element->GetNode(node_index)->AddElement(element_index);
00100         }
00101     }
00102 
00103     this->mMeshChangesDuringSimulation = false;
00104 }
00105 
00106 
00107 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00108 VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexMesh(std::vector<Node<SPACE_DIM>*> nodes,
00109                            std::vector<VertexElement<ELEMENT_DIM-1, SPACE_DIM>*> faces,
00110                            std::vector<VertexElement<ELEMENT_DIM, SPACE_DIM>*> vertexElements)
00111     : mpDelaunayMesh(NULL)
00112 {
00113     // Reset member variables and clear mNodes, mFaces and mElements
00114     Clear();
00115 
00116     // Populate mNodes mFaces and mElements
00117     for (unsigned node_index=0; node_index<nodes.size(); node_index++)
00118     {
00119         Node<SPACE_DIM>* p_temp_node = nodes[node_index];
00120         this->mNodes.push_back(p_temp_node);
00121     }
00122 
00123     for (unsigned face_index=0; face_index<faces.size(); face_index++)
00124     {
00125         VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_temp_face = faces[face_index];
00126         mFaces.push_back(p_temp_face);
00127     }
00128 
00129     for (unsigned elem_index=0; elem_index<vertexElements.size(); elem_index++)
00130     {
00131         VertexElement<ELEMENT_DIM, SPACE_DIM>* p_temp_vertex_element = vertexElements[elem_index];
00132         mElements.push_back(p_temp_vertex_element);
00133     }
00134 
00135     // Register elements with nodes
00136     for (unsigned index=0; index<mElements.size(); index++)
00137     {
00138         VertexElement<ELEMENT_DIM, SPACE_DIM>* p_temp_vertex_element = mElements[index];
00139         for (unsigned node_index=0; node_index<p_temp_vertex_element->GetNumNodes(); node_index++)
00140         {
00141             Node<SPACE_DIM>* p_temp_node = p_temp_vertex_element->GetNode(node_index);
00142             p_temp_node->AddElement(p_temp_vertex_element->GetIndex());
00143         }
00144     }
00145 
00146     this->mMeshChangesDuringSimulation = false;
00147 }
00148 
00149 
00155 template<>
00156 VertexMesh<2,2>::VertexMesh(TetrahedralMesh<2,2>& rMesh, bool isPeriodic)
00157     : mpDelaunayMesh(&rMesh)
00158 {
00159     if (!isPeriodic)        // If the mesh is non-periodic
00160     {
00161         // Reset member variables and clear mNodes, mFaces and mElements
00162         Clear();
00163     
00164         unsigned num_elements = mpDelaunayMesh->GetNumAllNodes();
00165         unsigned num_nodes = mpDelaunayMesh->GetNumAllElements();
00166     
00167         // Allocate memory for mNodes and mElements
00168         this->mNodes.reserve(num_nodes);
00169     
00170         // Create as many elements as there are nodes in the mesh
00171         mElements.reserve(num_elements);
00172         for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
00173         {
00174             VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index);
00175             mElements.push_back(p_element);
00176         }
00177     
00178         // Populate mNodes
00179         GenerateVerticesFromElementCircumcentres(rMesh);
00180     
00181         // Loop over elements of the Delaunay mesh
00182         for (unsigned i=0; i<num_nodes; i++)
00183         {
00184             // Loop over nodes owned by this element in the Delaunay mesh
00185             for (unsigned local_index=0; local_index<3; local_index++)
00186             {
00187                 unsigned elem_index = mpDelaunayMesh->GetElement(i)->GetNodeGlobalIndex(local_index);
00188                 unsigned num_nodes_in_elem = mElements[elem_index]->GetNumNodes();
00189                 unsigned end_index = num_nodes_in_elem>0 ? num_nodes_in_elem-1 : 0;
00190     
00191                 mElements[elem_index]->AddNode(end_index, this->mNodes[i]);
00192             }
00193         }
00194     
00195         // Reorder mNodes anticlockwise
00196         for (unsigned elem_index=0; elem_index<mElements.size(); elem_index++)
00197         {
00203             std::list<std::pair<unsigned, double> > index_angle_list;
00204             for (unsigned local_index=0; local_index<mElements[elem_index]->GetNumNodes(); local_index++)
00205             {
00206                 c_vector<double, 2> vectorA = mpDelaunayMesh->GetNode(elem_index)->rGetLocation();
00207                 c_vector<double, 2> vectorB = mElements[elem_index]->GetNodeLocation(local_index);
00208                 c_vector<double, 2> centre_to_vertex = mpDelaunayMesh->GetVectorFromAtoB(vectorA, vectorB);
00209     
00210                 double angle = atan2(centre_to_vertex(1), centre_to_vertex(0));
00211                 unsigned global_index = mElements[elem_index]->GetNodeGlobalIndex(local_index);
00212     
00213                 std::pair<unsigned, double> pair(global_index, angle);
00214                 index_angle_list.push_back(pair);
00215             }
00216     
00217             // Sort the list in order of increasing angle
00218             index_angle_list.sort(IndexAngleComparison);
00219     
00220             // Create a new Voronoi element and pass in the appropriate Nodes, ordered anticlockwise
00221             VertexElement<2,2>* p_new_element = new VertexElement<2,2>(elem_index);
00222             unsigned count = 0;
00223             for (std::list<std::pair<unsigned, double> >::iterator list_iter = index_angle_list.begin();
00224                  list_iter != index_angle_list.end();
00225                  ++list_iter)
00226             {
00227                 unsigned local_index = count>1 ? count-1 : 0;
00228                 p_new_element->AddNode(local_index, mNodes[list_iter->first]);
00229                 count++;
00230             }
00231     
00232             // Replace the relevant member of mElements with this Voronoi element
00233             delete mElements[elem_index];
00234             mElements[elem_index] = p_new_element;
00235         }
00236     
00237         this->mMeshChangesDuringSimulation = false;
00238     
00239     }
00240     
00241     else    // For a periodic crypt
00242     {       
00243         // Reset member variables and clear mNodes, mFaces and mElements
00244         Clear();
00245     
00246         unsigned num_elements = mpDelaunayMesh->GetNumAllNodes();
00247         unsigned num_nodes = mpDelaunayMesh->GetNumAllElements();
00248     
00249         // Allocate memory for mNodes and mElements
00250         this->mNodes.reserve(num_nodes);
00251     
00252         // Create as many elements as there are nodes in the mesh
00253         mElements.reserve(num_elements);
00254         for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
00255         {
00256             VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index);
00257             mElements.push_back(p_element);
00258         }
00259     
00260         // Populate mNodes
00261         GenerateVerticesFromElementCircumcentres(rMesh);
00262     
00263         // Loop over elements of the Delaunay mesh
00264         for (unsigned i=0; i<num_nodes; i++)
00265         {
00266             // Loop over nodes owned by this element in the Delaunay mesh
00267             for (unsigned local_index=0; local_index<3; local_index++)
00268             {
00269                 unsigned elem_index = mpDelaunayMesh->GetElement(i)->GetNodeGlobalIndex(local_index);
00270                 unsigned num_nodes_in_elem = mElements[elem_index]->GetNumNodes();
00271                 unsigned end_index = num_nodes_in_elem>0 ? num_nodes_in_elem-1 : 0;
00272     
00273                 mElements[elem_index]->AddNode(end_index, this->mNodes[i]);
00274             }
00275         }
00276     
00277         // Reorder mNodes anticlockwise
00278         for (unsigned elem_index=0; elem_index<mElements.size(); elem_index++)
00279         {
00285             std::list<std::pair<unsigned, double> > index_angle_list;
00286             for (unsigned local_index=0; local_index<mElements[elem_index]->GetNumNodes(); local_index++)
00287             {
00288                 c_vector<double, 2> vectorA = mpDelaunayMesh->GetNode(elem_index)->rGetLocation();
00289                 c_vector<double, 2> vectorB = mElements[elem_index]->GetNodeLocation(local_index);
00290                 c_vector<double, 2> centre_to_vertex = mpDelaunayMesh->GetVectorFromAtoB(vectorA, vectorB);
00291     
00292                 double angle = atan2(centre_to_vertex(1), centre_to_vertex(0));
00293                 unsigned global_index = mElements[elem_index]->GetNodeGlobalIndex(local_index);
00294     
00295                 std::pair<unsigned, double> pair(global_index, angle);
00296                 index_angle_list.push_back(pair);
00297             }
00298     
00299             // Sort the list in order of increasing angle
00300             index_angle_list.sort(IndexAngleComparison);
00301     
00302             // Create a new Voronoi element and pass in the appropriate Nodes, ordered anticlockwise
00303             VertexElement<2,2>* p_new_element = new VertexElement<2,2>(elem_index);
00304             unsigned count = 0;
00305             for (std::list<std::pair<unsigned, double> >::iterator list_iter = index_angle_list.begin();
00306                  list_iter != index_angle_list.end();
00307                  ++list_iter)
00308             {
00309                 unsigned local_index = count>1 ? count-1 : 0;
00310                 p_new_element->AddNode(local_index, mNodes[list_iter->first]);
00311                 count++;
00312             }
00313     
00314             // Replace the relevant member of mElements with this Voronoi element
00315             delete mElements[elem_index];
00316             mElements[elem_index] = p_new_element;
00317         }
00318     
00319         this->mMeshChangesDuringSimulation = false;     
00320     }
00321     
00322 }
00323 
00324 
00330 template<>
00331 VertexMesh<3,3>::VertexMesh(TetrahedralMesh<3,3>& rMesh)
00332     : mpDelaunayMesh(&rMesh)
00333 {
00334     // Reset member variables and clear mNodes, mFaces and mElements
00335     Clear();
00336 
00337     unsigned num_nodes = mpDelaunayMesh->GetNumAllElements();
00338 
00339     // Allocate memory for mNodes
00340     this->mNodes.reserve(num_nodes);
00341 
00342     // Populate mNodes
00343     GenerateVerticesFromElementCircumcentres(rMesh);
00344 
00345     std::map<unsigned, VertexElement<3,3>*> index_element_map;
00346     unsigned face_index = 0;
00347     unsigned element_index = 0;
00348 
00349     // Loop over each edge of the Delaunay mesh and populate mFaces and mElements
00350     for (TetrahedralMesh<3,3>::EdgeIterator edge_iterator = mpDelaunayMesh->EdgesBegin();
00351          edge_iterator != mpDelaunayMesh->EdgesEnd();
00352          ++edge_iterator)
00353     {
00354         Node<3>* p_node_a = edge_iterator.GetNodeA();
00355         Node<3>* p_node_b = edge_iterator.GetNodeB();
00356 
00357         if ( !(p_node_a->IsBoundaryNode() && p_node_b->IsBoundaryNode()) )
00358         {
00359             std::set<unsigned>& node_a_element_indices = p_node_a->rGetContainingElementIndices();
00360             std::set<unsigned>& node_b_element_indices = p_node_b->rGetContainingElementIndices();
00361             std::set<unsigned> edge_element_indices;
00362 
00363             std::set_intersection(node_a_element_indices.begin(),
00364                                   node_a_element_indices.end(),
00365                                   node_b_element_indices.begin(),
00366                                   node_b_element_indices.end(),
00367                                   std::inserter(edge_element_indices, edge_element_indices.begin()));
00368 
00369             c_vector<double,3> edge_vector = p_node_b->rGetLocation() - p_node_a->rGetLocation();
00370             c_vector<double,3> mid_edge = edge_vector*0.5 + p_node_a->rGetLocation();
00371 
00372             unsigned element0_index = *(edge_element_indices.begin());
00373 
00374             c_vector<double,3> basis_vector1 = mNodes[element0_index]->rGetLocation() - mid_edge;
00375 
00376             c_vector<double,3> basis_vector2;
00377             basis_vector2[0] = edge_vector[1]*basis_vector1[2] - edge_vector[2]*basis_vector1[1];
00378             basis_vector2[1] = edge_vector[2]*basis_vector1[0] - edge_vector[0]*basis_vector1[2];
00379             basis_vector2[2] = edge_vector[0]*basis_vector1[1] - edge_vector[1]*basis_vector1[0];
00380 
00386             std::list<std::pair<unsigned, double> > index_angle_list;
00387 
00388             // Loop over each element containing this edge (i.e. those containing both nodes of the edge)
00389             for (std::set<unsigned>::iterator index_iter = edge_element_indices.begin();
00390                  index_iter != edge_element_indices.end();
00391                  ++index_iter)
00392             {
00393                 // Calculate angle
00394                 c_vector<double, 3> vertex_vector =  mNodes[*index_iter]->rGetLocation() - mid_edge;
00395 
00396                 double local_vertex_dot_basis_vector1 = inner_prod(vertex_vector, basis_vector1);
00397                 double local_vertex_dot_basis_vector2 = inner_prod(vertex_vector, basis_vector2);
00398 
00399                 double angle = atan2(local_vertex_dot_basis_vector2, local_vertex_dot_basis_vector1);
00400 
00401                 std::pair<unsigned, double> pair(*index_iter, angle);
00402                 index_angle_list.push_back(pair);
00403             }
00404 
00405             // Sort the list in order of increasing angle
00406             index_angle_list.sort(IndexAngleComparison);
00407 
00408             // Create face
00409             VertexElement<2,3>* p_face = new VertexElement<2,3>(face_index);
00410             face_index++;
00411             unsigned count = 0;
00412             for (std::list<std::pair<unsigned, double> >::iterator list_iter = index_angle_list.begin();
00413                  list_iter != index_angle_list.end();
00414                  ++list_iter)
00415             {
00416                 unsigned local_index = count>1 ? count-1 : 0;
00417                 p_face->AddNode(local_index, mNodes[list_iter->first]);
00418                 count++;
00419             }
00420 
00421             // Add face to list of faces
00422             mFaces.push_back(p_face);
00423 
00424             // Add face to appropriate elements
00425             if (!p_node_a->IsBoundaryNode())
00426             {
00427                 unsigned node_a_index = p_node_a->GetIndex();
00428                 if (index_element_map[node_a_index])
00429                 {
00430                     // If there is already an element with this index, add the face to it...
00431                     index_element_map[node_a_index]->AddFace(p_face);
00432                 }
00433                 else
00434                 {
00435                     // ...otherwise create an element, add the face to it, and add to the map
00436                     mVoronoiElementIndexMap[node_a_index] = element_index;
00437                     VertexElement<3,3>* p_element = new VertexElement<3,3>(element_index);
00438                     element_index++;
00439                     p_element->AddFace(p_face);
00440                     index_element_map[node_a_index] = p_element;
00441                 }
00442             }
00443             if (!p_node_b->IsBoundaryNode())
00444             {
00445                 unsigned node_b_index = p_node_b->GetIndex();
00446                 if (index_element_map[node_b_index])
00447                 {
00448                     // If there is already an element with this index, add the face to it...
00449                     index_element_map[node_b_index]->AddFace(p_face);
00450                 }
00451                 else
00452                 {
00453                     // ...otherwise create an element, add the face to it, and add to the map
00454                     mVoronoiElementIndexMap[node_b_index] = element_index;
00455                     VertexElement<3,3>* p_element = new VertexElement<3,3>(element_index);
00456                     element_index++;
00457                     p_element->AddFace(p_face);
00458                     index_element_map[node_b_index] = p_element;
00459                 }
00460             }
00461         }
00462     }
00463 
00464     // Populate mElements
00465     unsigned elem_count = 0;
00466     for (std::map<unsigned, VertexElement<3,3>*>::iterator element_iter = index_element_map.begin();
00467          element_iter != index_element_map.end();
00468          ++element_iter)
00469     {
00470         mElements.push_back(element_iter->second);
00471         mVoronoiElementIndexMap[element_iter->first] = elem_count;
00472         elem_count++;
00473     }
00474 
00475     this->mMeshChangesDuringSimulation = false;
00476 }
00477 
00478 
00479 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00480 void VertexMesh<ELEMENT_DIM, SPACE_DIM>::GenerateVerticesFromElementCircumcentres(TetrahedralMesh<ELEMENT_DIM, SPACE_DIM>& rMesh)
00481 {
00482     c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
00483     c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
00484     double jacobian_det;
00485 
00486     // Loop over elements of the Delaunay mesh and populate mNodes
00487     for (unsigned i=0; i<rMesh.GetNumElements(); i++)
00488     {
00489         // Calculate the circumcentre of this element in the Delaunay mesh
00490         rMesh.GetInverseJacobianForElement(i, jacobian, jacobian_det, inverse_jacobian);
00491         c_vector<double, SPACE_DIM+1> circumsphere = rMesh.GetElement(i)->CalculateCircumsphere(jacobian, inverse_jacobian);
00492 
00493         c_vector<double, SPACE_DIM> circumcentre;
00494         for (unsigned j=0; j<SPACE_DIM; j++)
00495         {
00496             circumcentre(j) = circumsphere(j);
00497         }
00498 
00499         // Create a node in the Voronoi mesh at the location of this circumcentre
00500         this->mNodes.push_back(new Node<SPACE_DIM>(i, circumcentre));
00501     }
00502 }
00503 
00504 
00505 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00506 double VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetEdgeLength(unsigned elementIndex1, unsigned elementIndex2)
00507 {
00508     assert(SPACE_DIM==2);
00509 
00510     std::set<unsigned> node_indices_1;
00511     for (unsigned i=0; i<mElements[elementIndex1]->GetNumNodes(); i++)
00512     {
00513         node_indices_1.insert(mElements[elementIndex1]->GetNodeGlobalIndex(i));
00514     }
00515     std::set<unsigned> node_indices_2;
00516     for (unsigned i=0; i<mElements[elementIndex2]->GetNumNodes(); i++)
00517     {
00518         node_indices_2.insert(mElements[elementIndex2]->GetNodeGlobalIndex(i));
00519     }
00520 
00521     std::set<unsigned> shared_nodes;
00522     std::set_intersection(node_indices_1.begin(), node_indices_1.end(),
00523                           node_indices_2.begin(), node_indices_2.end(),
00524                           std::inserter(shared_nodes, shared_nodes.begin()));
00525 
00526     assert(shared_nodes.size() == 2);
00527 
00528     unsigned index1 = *(shared_nodes.begin());
00529     unsigned index2 = *(++(shared_nodes.begin()));
00530 
00531     c_vector<double, SPACE_DIM> node1_location = this->mNodes[index1]->rGetLocation();
00532     c_vector<double, SPACE_DIM> node2_location = this->mNodes[index2]->rGetLocation();
00533 
00534     double edge_length = norm_2(GetVectorFromAtoB(node1_location, node2_location));
00535     return edge_length;
00536 }
00537 
00538 
00539 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00540 VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexMesh()
00541 {
00542     mpDelaunayMesh = NULL;
00543     this->mMeshChangesDuringSimulation = false;
00544     Clear();
00545 }
00546 
00547 
00548 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00549 VertexMesh<ELEMENT_DIM, SPACE_DIM>::~VertexMesh()
00550 {
00551     Clear();
00552 }
00553 
00554 
00555 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00556 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::SolveNodeMapping(unsigned index) const
00557 {
00558     assert(index < this->mNodes.size());
00559     return index;
00560 }
00561 
00562 
00563 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00564 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::SolveElementMapping(unsigned index) const
00565 {
00566     assert(index < this->mElements.size());
00567     return index;
00568 }
00569 
00570 
00571 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00572 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::SolveBoundaryElementMapping(unsigned index) const
00573 {
00575 //    assert(index < this->mBoundaryElements.size() );
00576     return index;
00577 }
00578 
00579 
00580 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00581 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetDelaunayNodeIndexCorrespondingToVoronoiElementIndex(unsigned elementIndex)
00582 {
00583     unsigned node_index = UNSIGNED_UNSET;
00584 
00585     if (mVoronoiElementIndexMap.empty())
00586     {
00587         node_index = elementIndex;
00588     }
00589     else
00590     {
00591         for (std::map<unsigned, unsigned>::iterator iter = mVoronoiElementIndexMap.begin();
00592              iter != mVoronoiElementIndexMap.end();
00593              ++iter)
00594         {
00595             if (iter->second == elementIndex)
00596             {
00597                 node_index = iter->first;
00598                 break;
00599             }
00600         }
00601     }
00602     assert(node_index != UNSIGNED_UNSET);
00603     return node_index;
00604 }
00605 
00606 
00607 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00608 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetVoronoiElementIndexCorrespondingToDelaunayNodeIndex(unsigned nodeIndex)
00609 {
00610     unsigned element_index = UNSIGNED_UNSET;
00611 
00612     if (mVoronoiElementIndexMap.empty())
00613     {
00614         element_index = nodeIndex;
00615     }
00616     else
00617     {
00618         std::map<unsigned, unsigned>::iterator iter = mVoronoiElementIndexMap.find(nodeIndex);
00619 
00620         if (iter == mVoronoiElementIndexMap.end())
00621         {
00622             EXCEPTION("This index does not correspond to a VertexElement");
00623         }
00624         else
00625         {
00626             element_index = iter->second;
00627         }
00628     }
00629     assert(element_index != UNSIGNED_UNSET);
00630     return element_index;
00631 }
00632 
00633 
00634 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00635 void VertexMesh<ELEMENT_DIM, SPACE_DIM>::Clear()
00636 {
00637     // Delete elements
00638     for (unsigned i=0; i<mElements.size(); i++)
00639     {
00640         delete mElements[i];
00641     }
00642     mElements.clear();
00643 
00644     // Delete faces
00645     for (unsigned i=0; i<mFaces.size(); i++)
00646     {
00647         delete mFaces[i];
00648     }
00649     mFaces.clear();
00650 
00651     // Delete nodes
00652     for (unsigned i=0; i<this->mNodes.size(); i++)
00653     {
00654         delete this->mNodes[i];
00655     }
00656     this->mNodes.clear();
00657 }
00658 
00659 
00660 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00661 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNumNodes() const
00662 {
00663     return this->mNodes.size();
00664 }
00665 
00666 
00667 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00668 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNumElements() const
00669 {
00670     return mElements.size();
00671 }
00672 
00673 
00674 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00675 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNumAllElements() const
00676 {
00677     return mElements.size();
00678 }
00679 
00680 
00681 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00682 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNumFaces() const
00683 {
00684     return mFaces.size();
00685 }
00686 
00687 
00688 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00689 VertexElement<ELEMENT_DIM, SPACE_DIM>* VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetElement(unsigned index) const
00690 {
00691     assert(index < mElements.size());
00692     return mElements[index];
00693 }
00694 
00695 
00696 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00697 VertexElement<ELEMENT_DIM-1, SPACE_DIM>* VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetFace(unsigned index) const
00698 {
00699     assert(index < mFaces.size());
00700     return mFaces[index];
00701 }
00702 
00703 
00704 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00705 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetCentroidOfElement(unsigned index)
00706 {
00707     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
00708     unsigned num_nodes_in_element = p_element->GetNumNodes();
00709 
00710     c_vector<double, SPACE_DIM> centroid = zero_vector<double>(SPACE_DIM);
00711 
00712     switch (SPACE_DIM)
00713     {
00714         case 1:
00715         {
00716             centroid = 0.5*(p_element->GetNodeLocation(0) + p_element->GetNodeLocation(1));
00717         }
00718         break;
00719         case 2: 
00720         {
00721             c_vector<double, SPACE_DIM> current_node;
00722             c_vector<double, SPACE_DIM> anticlockwise_node;
00723 
00724             double temp_centroid_x = 0;
00725             double temp_centroid_y = 0;
00726 
00727             for (unsigned local_index=0; local_index<num_nodes_in_element; local_index++)
00728             {
00729                 // Find locations of current node and anticlockwise node
00730                 current_node = p_element->GetNodeLocation(local_index);
00731                 anticlockwise_node = p_element->GetNodeLocation((local_index+1)%num_nodes_in_element);
00732 
00733                 temp_centroid_x += (current_node[0]+anticlockwise_node[0])*(current_node[0]*anticlockwise_node[1]-current_node[1]*anticlockwise_node[0]);
00734                 temp_centroid_y += (current_node[1]+anticlockwise_node[1])*(current_node[0]*anticlockwise_node[1]-current_node[1]*anticlockwise_node[0]);
00735             }
00736 
00737             double vertex_area = GetVolumeOfElement(index);
00738             double centroid_coefficient = 1.0/(6.0*vertex_area);
00739 
00740             centroid(0) = centroid_coefficient*temp_centroid_x;
00741             centroid(1) = centroid_coefficient*temp_centroid_y;
00742         }
00743         break;
00744         case 3:
00745         {
00746             for (unsigned local_index=0; local_index<num_nodes_in_element; local_index++)
00747             {
00748                 centroid += p_element->GetNodeLocation(local_index);
00749             }
00750             centroid /= ((double) num_nodes_in_element);
00751         }
00752         break;
00753         default:
00754             NEVER_REACHED;
00755     }
00756     return centroid;
00757 }
00758 
00759 
00760 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00761 std::set<unsigned> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNeighbouringNodeIndices(unsigned nodeIndex)
00762 {
00763     // Create a set of neighbouring node indices
00764     std::set<unsigned> neighbouring_node_indices;
00765 
00766     // Find the indices of the elements owned by this node
00767     std::set<unsigned> containing_elem_indices = this->GetNode(nodeIndex)->rGetContainingElementIndices();
00768 
00769     // Iterate over these elements
00770     for (std::set<unsigned>::iterator elem_iter = containing_elem_indices.begin();
00771          elem_iter != containing_elem_indices.end();
00772          ++elem_iter)
00773     {
00774         // Find the local index of this node in this element
00775         unsigned local_index = GetElement(*elem_iter)->GetNodeLocalIndex(nodeIndex);
00776 
00777         // Find the global indices of the preceding and successive nodes in this element
00778         unsigned num_nodes = GetElement(*elem_iter)->GetNumNodes();
00779         unsigned previous_local_index = (local_index + num_nodes - 1)%num_nodes;
00780         unsigned next_local_index = (local_index + 1)%num_nodes;
00781 
00782         // Add the global indices of these two nodes to the set of neighbouring node indices
00783         neighbouring_node_indices.insert(GetElement(*elem_iter)->GetNodeGlobalIndex(previous_local_index));
00784         neighbouring_node_indices.insert(GetElement(*elem_iter)->GetNodeGlobalIndex(next_local_index));
00785     }
00786 
00787     return neighbouring_node_indices;
00788 }
00789 
00790 
00791 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00792 std::set<unsigned> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNeighbouringNodeNotAlsoInElement(unsigned nodeIndex, unsigned elemIndex)
00793 {
00794     // Get a pointer to this element
00795     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elemIndex);
00796 
00797     // Get the indices of the nodes contained in this element
00798     std::set<unsigned> node_indices_in_this_element;
00799     for (unsigned local_index=0; local_index<p_element->GetNumNodes(); local_index++)
00800     {
00801         unsigned global_index = p_element->GetNodeGlobalIndex(local_index);
00802         node_indices_in_this_element.insert(global_index);
00803     }
00804 
00805     // Check that the node is in fact contained in the element
00806     if (node_indices_in_this_element.find(nodeIndex) == node_indices_in_this_element.end())
00807     {
00808         EXCEPTION("The given node is not contained in the given element.");
00809     }
00810 
00811     // Create a set of neighbouring node indices
00812     std::set<unsigned> neighbouring_node_indices_not_in_this_element;
00813 
00814     // Get the indices of this node's neighbours
00815     std::set<unsigned> node_neighbours = GetNeighbouringNodeIndices(nodeIndex);
00816 
00817     // Check if each neighbour is also in this element; if not, add it to the set
00818     for (std::set<unsigned>::iterator iter = node_neighbours.begin();
00819          iter != node_neighbours.end();
00820          ++iter)
00821     {
00822         if (node_indices_in_this_element.find(*iter) == node_indices_in_this_element.end())
00823         {
00824             neighbouring_node_indices_not_in_this_element.insert(*iter);
00825         }
00826     }
00827 
00828     return neighbouring_node_indices_not_in_this_element;
00829 }
00830 
00831 
00832 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
00833 std::set<unsigned> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNeighbouringElementIndices(unsigned elementIndex)
00834 {
00835     // Get a pointer to this element
00836     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elementIndex);
00837 
00838     // Create a set of neighbouring element indices
00839     std::set<unsigned> neighbouring_element_indices;
00840 
00841     // Loop over nodes owned by this element
00842     for (unsigned local_index=0; local_index<p_element->GetNumNodes(); local_index++)
00843     {
00844         // Get a pointer to this node
00845         Node<SPACE_DIM>* p_node = p_element->GetNode(local_index);
00846 
00847         // Find the indices of the elements owned by this node
00848         std::set<unsigned> containing_elem_indices = p_node->rGetContainingElementIndices();
00849 
00850         // Form the union of this set with the current set of neighbouring element indices
00851         std::set<unsigned> all_elements;
00852         std::set_union(neighbouring_element_indices.begin(), neighbouring_element_indices.end(),
00853                        containing_elem_indices.begin(), containing_elem_indices.end(),
00854                        std::inserter(all_elements, all_elements.begin()));
00855 
00856         // Update the set of neighbouring element indices
00857         neighbouring_element_indices = all_elements;
00858     }
00859 
00860     // Lastly remove this element's index from the set of neighbouring element indices
00861     neighbouring_element_indices.erase(elementIndex);
00862 
00863     return neighbouring_element_indices;
00864 }
00865 
00866 
00868 template<>
00869 void VertexMesh<1,1>::ConstructFromMeshReader(AbstractMeshReader<1,1>& rMeshReader)
00871 {
00872 }
00873 
00875 template<>
00876 void VertexMesh<1,2>::ConstructFromMeshReader(AbstractMeshReader<1,2>& rMeshReader)
00878 {
00879 }
00880 
00882 template<>
00883 void VertexMesh<1,3>::ConstructFromMeshReader(AbstractMeshReader<1,3>& rMeshReader)
00885 {
00886 }
00887 
00889 template<>
00890 void VertexMesh<2,3>::ConstructFromMeshReader(AbstractMeshReader<2,3>& rMeshReader)
00892 {
00893 }
00894 
00896 template<>
00897 void VertexMesh<2,2>::ConstructFromMeshReader(AbstractMeshReader<2,2>& rMeshReader)
00899 {
00900     // Store numbers of nodes and elements
00901     unsigned num_nodes = rMeshReader.GetNumNodes();
00902     unsigned num_elements = rMeshReader.GetNumElements();
00903 
00904     // Reserve memory for nodes
00905     this->mNodes.reserve(num_nodes);
00906 
00907     rMeshReader.Reset();
00908 
00909     // Add nodes
00910     std::vector<double> node_data;
00911     for (unsigned i=0; i<num_nodes; i++)
00912     {
00913         node_data = rMeshReader.GetNextNode();
00914         unsigned is_boundary_node = (unsigned) node_data[2];
00915         node_data.pop_back();
00916         this->mNodes.push_back(new Node<2>(i, node_data, is_boundary_node));
00917     }
00918 
00919     rMeshReader.Reset();
00920 
00921     // Reserve memory for nodes
00922     mElements.reserve(rMeshReader.GetNumElements());
00923 
00924     // Add elements
00925     for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
00926     {
00927         // Get the data for this element
00928         ElementData element_data = rMeshReader.GetNextElementData();
00929 
00930         // Get the nodes owned by this element
00931         std::vector<Node<2>*> nodes;
00932         unsigned num_nodes_in_element = element_data.NodeIndices.size();
00933         for (unsigned j=0; j<num_nodes_in_element; j++)
00934         {
00935             assert(element_data.NodeIndices[j] < this->mNodes.size());
00936             nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
00937         }
00938 
00939         // Use nodes and index to construct this element
00940         VertexElement<2,2>* p_element = new VertexElement<2,2>(elem_index, nodes);
00941         mElements.push_back(p_element);
00942 
00943         if (rMeshReader.GetNumElementAttributes() > 0)
00944         {
00945             assert(rMeshReader.GetNumElementAttributes() == 1);
00946             unsigned attribute_value = element_data.AttributeValue;
00947             p_element->SetRegion(attribute_value);
00948         }
00949     }
00950 }
00951 
00953 template<>
00954 void VertexMesh<3,3>::ConstructFromMeshReader(AbstractMeshReader<3,3>& rMeshReader)
00956 {
00957     // Store numbers of nodes and elements
00958     unsigned num_nodes = rMeshReader.GetNumNodes();
00959     unsigned num_elements = rMeshReader.GetNumElements();
00960 
00961     // Reserve memory for nodes
00962     this->mNodes.reserve(num_nodes);
00963 
00964     rMeshReader.Reset();
00965 
00966     // Add nodes
00967     std::vector<double> node_data;
00968     for (unsigned i=0; i<num_nodes; i++)
00969     {
00970         node_data = rMeshReader.GetNextNode();
00971         unsigned is_boundary_node = (unsigned) node_data[3];
00972         node_data.pop_back();
00973         this->mNodes.push_back(new Node<3>(i, node_data, is_boundary_node));
00974     }
00975 
00976     rMeshReader.Reset();
00977 
00978     // Reserve memory for nodes
00979     mElements.reserve(rMeshReader.GetNumElements());
00980 
00981     // Use a std::set to keep track of which faces have been added to mFaces
00982     std::set<unsigned> faces_counted;
00983 
00984     // Add elements
00985     for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
00986     {
00988         typedef VertexMeshReader<3,3> VERTEX_MESH_READER;
00989         assert(dynamic_cast<VERTEX_MESH_READER*>(&rMeshReader) != NULL);
00990 
00991         // Get the data for this element
00992         VertexElementData element_data = static_cast<VERTEX_MESH_READER*>(&rMeshReader)->GetNextElementDataWithFaces();
00993 
00994         // Get the nodes owned by this element
00995         std::vector<Node<3>*> nodes;
00996         unsigned num_nodes_in_element = element_data.NodeIndices.size();
00997         for (unsigned j=0; j<num_nodes_in_element; j++)
00998         {
00999             assert(element_data.NodeIndices[j] < this->mNodes.size());
01000             nodes.push_back(this->mNodes[element_data.NodeIndices[j]]);
01001         }
01002 
01003         // Get the faces owned by this element
01004         std::vector<VertexElement<2,3>*> faces;
01005         unsigned num_faces_in_element = element_data.Faces.size();
01006         for (unsigned i=0; i<num_faces_in_element; i++)
01007         {
01008             // Get the data for this face
01009             ElementData face_data = element_data.Faces[i];
01010 
01011             // Get the face index
01012             unsigned face_index = face_data.AttributeValue;
01013 
01014             // Get the nodes owned by this face
01015             std::vector<Node<3>*> nodes_in_face;
01016             unsigned num_nodes_in_face = face_data.NodeIndices.size();
01017             for (unsigned j=0; j<num_nodes_in_face; j++)
01018             {
01019                 assert(face_data.NodeIndices[j] < this->mNodes.size());
01020                 nodes_in_face.push_back(this->mNodes[face_data.NodeIndices[j]]);
01021             }
01022 
01023             // If this face index is not already encountered, create a new face and update faces_counted...
01024             if (faces_counted.find(face_index) == faces_counted.end())
01025             {
01026                 // Use nodes and index to construct this face
01027                 VertexElement<2,3>* p_face = new VertexElement<2,3>(face_index, nodes_in_face);
01028                 mFaces.push_back(p_face);
01029                 faces_counted.insert(face_index);
01030                 faces.push_back(p_face);
01031             }
01032             else
01033             {
01034                 // ... otherwise use the member of mFaces with this index
01035                 bool face_added = false;
01036                 for (unsigned k=0; k<mFaces.size(); k++)
01037                 {
01038                     if (mFaces[k]->GetIndex() == face_index)
01039                     {
01040                         faces.push_back(mFaces[k]);
01041                         face_added = true;
01042                         break;
01043                     }
01044                 }
01045                 assert(face_added == true);
01046             }
01047         }
01048 
01050         std::vector<bool> orientations = std::vector<bool>(num_faces_in_element, true);
01051 
01052         // Use faces and index to construct this element
01053         VertexElement<3,3>* p_element = new VertexElement<3,3>(elem_index, faces, orientations, nodes);
01054         mElements.push_back(p_element);
01055 
01056         if (rMeshReader.GetNumElementAttributes() > 0)
01057         {
01058             assert(rMeshReader.GetNumElementAttributes() == 1);
01059             unsigned attribute_value = element_data.AttributeValue;
01060             p_element->SetRegion(attribute_value);
01061         }
01062     }
01063 }
01064 
01065 
01066 template <unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01067 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetVectorFromAtoB(
01068     const c_vector<double, SPACE_DIM>& rLocationA, const c_vector<double, SPACE_DIM>& rLocationB)
01069 {
01070     c_vector<double, SPACE_DIM> vector;
01071     if (mpDelaunayMesh)
01072     {
01073         vector = mpDelaunayMesh->GetVectorFromAtoB(rLocationA, rLocationB);
01074     }
01075     else
01076     {
01077         vector = AbstractMesh<ELEMENT_DIM, SPACE_DIM>::GetVectorFromAtoB(rLocationA, rLocationB);
01078     }
01079     return vector;
01080 }
01081 
01082 
01083 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01084 double VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetVolumeOfElement(unsigned index)
01085 {
01086     assert(SPACE_DIM == 2 || SPACE_DIM == 3);
01087 
01088     // Get pointer to this element
01089     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
01090 
01091     double element_volume = 0.0;
01092     if (SPACE_DIM == 2)
01093     {
01094         c_vector<double, SPACE_DIM> first_node = p_element->GetNodeLocation(0);
01095 
01096         unsigned num_nodes_in_element = p_element->GetNumNodes();
01097 
01098         for (unsigned local_index=0; local_index<num_nodes_in_element; local_index++)
01099         {
01100             // Find locations of current node and anticlockwise node
01101             c_vector<double, SPACE_DIM> current_node = p_element->GetNodeLocation(local_index);
01102             c_vector<double, SPACE_DIM> anticlockwise_node = p_element->GetNodeLocation((local_index+1)%num_nodes_in_element);
01103 
01104             /*
01105              * In order to calculate the area we map the origin to (x[0],y[0])
01106              * then use GetVectorFromAtoB() to get node cooordiantes
01107              */
01108             c_vector<double, SPACE_DIM> transformed_current_node = GetVectorFromAtoB(first_node, current_node);
01109             c_vector<double, SPACE_DIM> transformed_anticlockwise_node = GetVectorFromAtoB(first_node, anticlockwise_node);
01110 
01111             element_volume += 0.5*(transformed_current_node[0]*transformed_anticlockwise_node[1]
01112                                    - transformed_anticlockwise_node[0]*transformed_current_node[1]);
01113         }
01114     }
01115     else
01116     {
01117         // Loop over faces and add up pyramid volumes
01118         c_vector<double, SPACE_DIM> pyramid_apex = p_element->GetNodeLocation(0);
01119         for (unsigned face_index=0; face_index<p_element->GetNumFaces(); face_index++)
01120         {
01121             // Get pointer to face
01122             VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_face = p_element->GetFace(face_index);
01123 
01124             // Get unit normal to this face
01125             c_vector<double, SPACE_DIM> unit_normal = GetUnitNormalToFace(p_face);
01126 
01127             // Calculate the perpendicular distance from the plane of the face to the chosen apex
01128             c_vector<double, SPACE_DIM> base_to_apex = GetVectorFromAtoB(p_face->GetNodeLocation(0), pyramid_apex);
01129             double perpendicular_distance = inner_prod(base_to_apex, unit_normal);
01130 
01131             // Calculate the area of the face
01132             double face_area = GetAreaOfFace(p_face);
01133 
01134             // Use these to calculate the volume of the pyramid formed by the face and the point pyramid_apex
01135             element_volume += face_area * perpendicular_distance / 3;
01136         }
01137     }
01138     return fabs(element_volume);
01139 }
01140 
01141 
01142 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01143 double VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetSurfaceAreaOfElement(unsigned index)
01144 {
01145     assert(SPACE_DIM == 2 || SPACE_DIM == 3);
01146 
01147     // Get pointer to this element
01148     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
01149 
01150     double surface_area = 0.0;
01151     if (SPACE_DIM == 2)
01152     {
01153         unsigned num_nodes_in_element = p_element->GetNumNodes();
01154         for (unsigned local_index=0; local_index<num_nodes_in_element; local_index++)
01155         {
01156             // Find locations of current node and anticlockwise node
01157             unsigned current_node_index = p_element->GetNodeGlobalIndex(local_index);
01158             unsigned anticlockwise_node_index = p_element->GetNodeGlobalIndex((local_index+1)%num_nodes_in_element);
01159 
01160             surface_area += this->GetDistanceBetweenNodes(current_node_index, anticlockwise_node_index);
01161         }
01162     }
01163     else
01164     {
01165         // Loop over faces and add up areas
01166         for (unsigned face_index=0; face_index<p_element->GetNumFaces(); face_index++)
01167         {
01168             surface_area += GetAreaOfFace(p_element->GetFace(face_index));
01169         }
01170     }
01171     return surface_area;
01172 }
01173 
01174 
01176 //                        2D-specific methods                       //
01178 
01179 
01180 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01181 bool VertexMesh<ELEMENT_DIM, SPACE_DIM>::ElementIncludesPoint(const c_vector<double, SPACE_DIM>& rTestPoint, unsigned elementIndex)
01182 {
01183     // Make sure that we are in the correct dimension - this code will be eliminated at compile time
01184     assert(SPACE_DIM == 2); // only works in 2D at present
01185     assert(ELEMENT_DIM == SPACE_DIM);
01186 
01187     // Initialise boolean
01188     bool element_includes_point = false;
01189 
01190     // Get the element
01191     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(elementIndex);
01192     unsigned num_nodes = p_element->GetNumNodes();
01193 
01194     // Remap the origin to the first vertex to allow alternative distance metrics to be used in subclasses
01195     c_vector<double, SPACE_DIM> first_vertex = p_element->GetNodeLocation(0);
01196 
01197     c_vector<double, SPACE_DIM> test_point =  GetVectorFromAtoB(first_vertex,rTestPoint);
01198 
01199     // Loop over edges of the element
01200     for (unsigned local_index=0; local_index<num_nodes; local_index++)
01201     {
01202         // Get the end points of this edge
01203         // Remap to the origin to allow alternative distance metrics to be used in subclasses
01204         c_vector<double, SPACE_DIM> vertexA = GetVectorFromAtoB(first_vertex, p_element->GetNodeLocation(local_index));
01205         c_vector<double, SPACE_DIM> vertexB = GetVectorFromAtoB(first_vertex, p_element->GetNodeLocation((local_index+1)%num_nodes));
01206 
01207 
01208         // Check if this edge crosses the ray running out horizontally (increasing x, fixed y) from the test point
01209         c_vector<double, SPACE_DIM> vector_a_to_point = GetVectorFromAtoB(vertexA, test_point);
01210         c_vector<double, SPACE_DIM> vector_b_to_point = GetVectorFromAtoB(vertexB, test_point);
01211         c_vector<double, SPACE_DIM> vector_a_to_b = GetVectorFromAtoB(vertexA, vertexB);
01212 
01213         // Pathological case - test point coincides with vertexA or vertexB
01214         if (    (norm_2(vector_a_to_point) < DBL_EPSILON)
01215              || (norm_2(vector_b_to_point) < DBL_EPSILON) )
01216         {
01217             return false;
01218         }
01219 
01220         // Pathological case - ray coincides with horizontal edge
01221         if ( (fabs(vector_a_to_b[1]) < DBL_EPSILON) &&
01222              (fabs(vector_a_to_point[1]) < DBL_EPSILON) &&
01223              (fabs(vector_b_to_point[1]) < DBL_EPSILON) )
01224         {
01225             if ( (vector_a_to_point[0]>0) != (vector_b_to_point[0]>0) )
01226             {
01227                 return false;
01228             }
01229         }
01230 
01231         // Non-pathological case
01232         // A and B on different sides of the line y = test_point[1]
01233         if ( (vertexA[1] > test_point[1]) != (vertexB[1] > test_point[1]) )
01234         {
01235             // intersection of y=test_point[1] and vector_a_to_b is on the Right of test_point
01236             if (test_point[0] < vertexA[0] + vector_a_to_b[0]*vector_a_to_point[1]/vector_a_to_b[1])
01237             {
01238                 element_includes_point = !element_includes_point;
01239             }
01240         }
01241     }
01242     return element_includes_point;
01243 }
01244 
01245 
01246 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01247 unsigned VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetLocalIndexForElementEdgeClosestToPoint(const c_vector<double, SPACE_DIM>& rTestPoint, unsigned elementIndex)
01248 {
01249     // Make sure that we are in the correct dimension - this code will be eliminated at compile time
01250     assert(SPACE_DIM == 2); // only works in 2D at present
01251     assert(ELEMENT_DIM == SPACE_DIM);
01252 
01253     // Get the element
01254     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(elementIndex);
01255     unsigned num_nodes = p_element->GetNumNodes();
01256 
01257     double min_squared_normal_distance = DBL_MAX;
01258     unsigned min_distance_edge_index = UINT_MAX;
01259 
01260     // Loop over edges of the element
01261     for (unsigned local_index=0; local_index<num_nodes; local_index++)
01262     {
01263         // Get the end points of this edge
01264         c_vector<double, SPACE_DIM> vertexA = p_element->GetNodeLocation(local_index);
01265         c_vector<double, SPACE_DIM> vertexB = p_element->GetNodeLocation((local_index+1)%num_nodes);
01266 
01267         c_vector<double, SPACE_DIM> vector_a_to_point = this->GetVectorFromAtoB(vertexA, rTestPoint);
01268         c_vector<double, SPACE_DIM> vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB);
01269 
01270         c_vector<double, SPACE_DIM> edge_ab_unit_vector = vector_a_to_b/norm_2(vector_a_to_b);
01271         double distance_parallel_to_edge = inner_prod(vector_a_to_point, edge_ab_unit_vector);
01272 
01273         double squared_distance_normal_to_edge = SmallPow(norm_2(vector_a_to_point), 2) - SmallPow(distance_parallel_to_edge, 2);
01274 
01275         // Make sure node is within the confines of the edge and is the nearest edge to the node \this breks for convex elements
01276         if (squared_distance_normal_to_edge < min_squared_normal_distance &&
01277             distance_parallel_to_edge >=0 &&
01278             distance_parallel_to_edge <= norm_2(vector_a_to_b))
01279         {
01280             min_squared_normal_distance = squared_distance_normal_to_edge;
01281             min_distance_edge_index = local_index;
01282         }
01283     }
01284     return min_distance_edge_index;
01285 }
01286 
01287 
01288 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01289 c_vector<double, 3> VertexMesh<ELEMENT_DIM, SPACE_DIM>::CalculateMomentsOfElement(unsigned index)
01290 {
01291     assert(SPACE_DIM == 2);
01292 
01293     VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = GetElement(index);
01294     unsigned num_nodes_in_element = p_element->GetNumNodes();
01295     c_vector<double, 2> centroid = GetCentroidOfElement(index);
01296 
01297     c_vector<double, 3> moments = zero_vector<double>(3);
01298 
01299     unsigned node_1;
01300     unsigned node_2;
01301 
01302     for (unsigned local_index=0; local_index<num_nodes_in_element; local_index++)
01303     {
01304         node_1 = local_index;
01305         node_2 = (local_index+1)%num_nodes_in_element;
01306 
01307         // Original position of nodes
01308         c_vector<double, 2> original_pos_1 = p_element->GetNodeLocation(node_1);
01309         c_vector<double, 2> original_pos_2 = p_element->GetNodeLocation(node_2);
01310 
01311         // Node position so centerd on origin
01312         c_vector<double, 2> pos_1 = this->GetVectorFromAtoB(centroid, original_pos_1);
01313         c_vector<double, 2> pos_2 = this->GetVectorFromAtoB(centroid, original_pos_2);
01314 
01315         /*
01316          * Note these formulae require the polygon to be centered on the origin
01317          */
01318         double a = pos_1(0)*pos_2(1)-pos_2(0)*pos_1(1);
01319 
01320         // Ixx
01321         moments(0) += (  pos_1(1)*pos_1(1)
01322                        + pos_1(1)*pos_2(1)
01323                        + pos_2(1)*pos_2(1) ) * a;
01324 
01325         // Iyy
01326         moments(1) += (  pos_1(0)*pos_1(0)
01327                        + pos_1(0)*pos_2(0)
01328                        + pos_2(0)*pos_2(0) ) * a;
01329 
01330         // Ixy
01331         moments(2) += (  pos_1(0)*pos_2(1)
01332                        + 2*pos_1(0)*pos_1(1)
01333                        + 2*pos_2(0)*pos_2(1)
01334                        + pos_2(0)*pos_1(1) ) * a;
01335     }
01336 
01337     moments(0) /= 12;
01338     moments(1) /= 12;
01339     moments(2) /= 24;
01340 
01341     return moments;
01342 }
01343 
01344 
01345 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01346 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetShortAxisOfElement(unsigned index)
01347 {
01348     assert(SPACE_DIM == 2);
01349 
01350     c_vector<double, SPACE_DIM> short_axis = zero_vector<double>(SPACE_DIM);
01351     c_vector<double, 3> moments = CalculateMomentsOfElement(index);
01352 
01353     double largest_eigenvalue, discriminant;
01354 
01355     discriminant = sqrt((moments(0) - moments(1))*(moments(0) - moments(1)) + 4.0*moments(2)*moments(2));
01356     // This is always the largest eigenvalue as both eigenvalues are real as it is a
01357     // symmetric matrix
01358     largest_eigenvalue = (moments(0) + moments(1) + discriminant)*0.5;
01359     if (fabs(discriminant) < 1e-10)
01360     {
01361         // Return a random unit vector
01362         short_axis(0) = RandomNumberGenerator::Instance()->ranf();
01363         short_axis(1) = sqrt(1.0 - short_axis(0)*short_axis(0));
01364     }
01365     else
01366     {
01367         if (moments(2) == 0.0)
01368         {
01369             short_axis(0) = (moments(0) < moments(1)) ? 0.0 : 1.0;
01370             short_axis(1) = (moments(0) < moments(1)) ? 1.0 : 0.0;
01371         }
01372         else
01373         {
01374             short_axis(0) = 1.0;
01375             short_axis(1) = (moments(0) - largest_eigenvalue)/moments(2);
01376 
01377             double length_short_axis = norm_2(short_axis);
01378 
01379             short_axis /= length_short_axis;
01380         }
01381     }
01382     return short_axis;
01383 }
01384 
01385 
01386 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01387 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetAreaGradientOfElementAtNode(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, unsigned localIndex)
01388 {
01389     assert(SPACE_DIM==2);
01390 
01391     unsigned num_nodes_in_element = pElement->GetNumNodes();
01392     unsigned next_local_index = (localIndex+1)%num_nodes_in_element;
01393 
01394     // We add an extra num_nodes_in_element in the line below as otherwise this term can be negative, which breaks the % operator
01395     unsigned previous_local_index = (num_nodes_in_element+localIndex-1)%num_nodes_in_element;
01396 
01397     c_vector<double, SPACE_DIM> previous_node_location = pElement->GetNodeLocation(previous_local_index);
01398     c_vector<double, SPACE_DIM> next_node_location = pElement->GetNodeLocation(next_local_index);
01399     c_vector<double, SPACE_DIM> difference_vector = this->GetVectorFromAtoB(previous_node_location, next_node_location);
01400 
01401     c_vector<double, SPACE_DIM> area_gradient;
01402 
01403     area_gradient[0] = 0.5*difference_vector[1];
01404     area_gradient[1] = -0.5*difference_vector[0];
01405 
01406     return area_gradient;
01407 }
01408 
01409 
01410 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01411 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetPreviousEdgeGradientOfElementAtNode(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, unsigned localIndex)
01412 {
01413     assert(SPACE_DIM==2);
01414 
01415     unsigned num_nodes_in_element = pElement->GetNumNodes();
01416 
01417     // We add an extra localIndex-1 in the line below as otherwise this term can be negative, which breaks the % operator
01418     unsigned previous_local_index = (num_nodes_in_element+localIndex-1)%num_nodes_in_element;
01419 
01420     unsigned current_global_index = pElement->GetNodeGlobalIndex(localIndex);
01421     unsigned previous_global_index = pElement->GetNodeGlobalIndex(previous_local_index);
01422 
01423     double previous_edge_length = this->GetDistanceBetweenNodes(current_global_index, previous_global_index);
01424     assert(previous_edge_length > DBL_EPSILON);
01425 
01426     c_vector<double, SPACE_DIM> previous_edge_gradient = this->GetVectorFromAtoB(pElement->GetNodeLocation(previous_local_index), pElement->GetNodeLocation(localIndex))/previous_edge_length;
01427 
01428     return previous_edge_gradient;
01429 }
01430 
01431 
01432 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01433 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNextEdgeGradientOfElementAtNode(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, unsigned localIndex)
01434 {
01435     assert(SPACE_DIM==2);
01436 
01437     unsigned next_local_index = (localIndex+1)%(pElement->GetNumNodes());
01438 
01439     unsigned current_global_index = pElement->GetNodeGlobalIndex(localIndex);
01440     unsigned next_global_index = pElement->GetNodeGlobalIndex(next_local_index);
01441 
01442     double next_edge_length = this->GetDistanceBetweenNodes(current_global_index, next_global_index);
01443     assert(next_edge_length > DBL_EPSILON);
01444 
01445     c_vector<double, SPACE_DIM> next_edge_gradient = this->GetVectorFromAtoB(pElement->GetNodeLocation(next_local_index), pElement->GetNodeLocation(localIndex))/next_edge_length;
01446 
01447     return next_edge_gradient;
01448 }
01449 
01450 
01451 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01452 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetPerimeterGradientOfElementAtNode(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, unsigned localIndex)
01453 {
01454     assert(SPACE_DIM==2);
01455 
01456     c_vector<double, SPACE_DIM> previous_edge_gradient = GetPreviousEdgeGradientOfElementAtNode(pElement, localIndex);
01457     c_vector<double, SPACE_DIM> next_edge_gradient = GetNextEdgeGradientOfElementAtNode(pElement, localIndex);
01458 
01459     return previous_edge_gradient + next_edge_gradient;
01460 }
01461 
01462 
01464 //                        3D-specific methods                       //
01466 
01467 
01468 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01469 c_vector<double, SPACE_DIM> VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetUnitNormalToFace(VertexElement<ELEMENT_DIM-1, SPACE_DIM>* pFace)
01470 {
01471     assert(SPACE_DIM == 3);
01472 
01473     // As we are in 3D, the face must have at least three vertices, so use its first three vertices
01474     c_vector<double, SPACE_DIM> v0 = pFace->GetNode(0)->rGetLocation();
01475     c_vector<double, SPACE_DIM> v1 = pFace->GetNode(1)->rGetLocation();
01476     c_vector<double, SPACE_DIM> v2 = pFace->GetNode(2)->rGetLocation();
01477 
01478     c_vector<double, SPACE_DIM> v1_minus_v0 = this->GetVectorFromAtoB(v0, v1);
01479     c_vector<double, SPACE_DIM> v2_minus_v0 = this->GetVectorFromAtoB(v0, v2);
01480 
01481     c_vector<double, SPACE_DIM> unit_normal = zero_vector<double>(SPACE_DIM);
01482     unit_normal(0) = v1_minus_v0(1)*v2_minus_v0(2) - v1_minus_v0(2)*v2_minus_v0(1);
01483     unit_normal(1) = v1_minus_v0(2)*v2_minus_v0(0) - v1_minus_v0(0)*v2_minus_v0(2);
01484     unit_normal(2) = v1_minus_v0(0)*v2_minus_v0(1) - v1_minus_v0(1)*v2_minus_v0(0);
01485 
01486     // Normalize the normal vector
01487     unit_normal /= norm_2(unit_normal);
01488 
01489     return unit_normal;
01490 }
01491 
01492 
01493 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM>
01494 double VertexMesh<ELEMENT_DIM, SPACE_DIM>::GetAreaOfFace(VertexElement<ELEMENT_DIM-1, SPACE_DIM>* pFace)
01495 {
01496     assert(SPACE_DIM == 3);
01497 
01498     // Get the unit normal to the plane of this face
01499     c_vector<double, SPACE_DIM> unit_normal = GetUnitNormalToFace(pFace);
01500 
01501     // Select the largest absolute coordinate to ignore for planar projection
01502     double abs_x = unit_normal[0]>0 ? unit_normal[0]>0 : -unit_normal[0];
01503     double abs_y = unit_normal[1]>0 ? unit_normal[1]>0 : -unit_normal[1];
01504     double abs_z = unit_normal[2]>0 ? unit_normal[2]>0 : -unit_normal[2];
01505 
01506     unsigned dim_to_ignore = 2; // ignore z coordinate
01507     double abs = abs_z;
01508 
01509     if (abs_x > abs_y)
01510     {
01511         if (abs_x > abs_z)
01512         {
01513             dim_to_ignore = 0; // ignore x coordinate
01514             abs = abs_x;
01515         }
01516     }
01517     else if (abs_y > abs_z)
01518     {
01519         dim_to_ignore = 1; // ignore y coordinate
01520         abs = abs_y;
01521     }
01522 
01523     // Compute area of the 2D projection
01524     c_vector<double, SPACE_DIM-1> current_vertex;
01525     c_vector<double, SPACE_DIM-1> anticlockwise_vertex;
01526 
01527     unsigned num_nodes_in_face = pFace->GetNumNodes();
01528 
01529     unsigned dim1 = dim_to_ignore==0 ? 1 : 0;
01530     unsigned dim2 = dim_to_ignore==2 ? 1 : 2;
01531 
01532     double face_area = 0.0;
01533     for (unsigned local_index=0; local_index<num_nodes_in_face; local_index++)
01534     {
01535         // Find locations of current vertex and anticlockwise vertex
01536         current_vertex[0] = pFace->GetNodeLocation(local_index, dim1);
01537         current_vertex[1] = pFace->GetNodeLocation(local_index, dim2);
01538         anticlockwise_vertex[0] = pFace->GetNodeLocation((local_index+1)%num_nodes_in_face, dim1);
01539         anticlockwise_vertex[1] = pFace->GetNodeLocation((local_index+1)%num_nodes_in_face, dim2);
01540 
01541         // It doesn't matter if the face is oriented clockwise or not, since we area only interested in the area
01542         face_area += 0.5*(current_vertex[0]*anticlockwise_vertex[1] - anticlockwise_vertex[0]*current_vertex[1]);
01543     }
01544 
01545     // Scale to get area before projection
01546     face_area /= abs;
01547     return fabs(face_area);
01548 }
01550 #if defined(__xlC__)
01551 template<>
01552 double VertexMesh<1,1>::GetAreaOfFace(VertexElement<0,1>* pFace)
01553 {
01554     NEVER_REACHED;
01555 }
01556 #endif
01557 
01558 
01560 // Explicit instantiation
01562 
01563 template class VertexMesh<1,1>;
01564 template class VertexMesh<1,2>;
01565 template class VertexMesh<1,3>;
01566 template class VertexMesh<2,2>;
01567 template class VertexMesh<2,3>;
01568 template class VertexMesh<3,3>;
01569 
01570 
01571 // Serialization for Boost >= 1.36
01572 #include "SerializationExportWrapperForCpp.hpp"
01573 EXPORT_TEMPLATE_CLASS_ALL_DIMS(VertexMesh)

Generated on Mon Nov 1 12:35:24 2010 for Chaste by  doxygen 1.5.5