VertexMesh.cpp

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

Generated by  doxygen 1.6.2