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