VertexMesh.cpp

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