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