VertexMesh.cpp

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

Generated by  doxygen 1.6.2