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 "MutableVertexMesh.hpp" 00037 #include "RandomNumberGenerator.hpp" 00038 #include "UblasCustomFunctions.hpp" 00039 #include "Warnings.hpp" 00040 #include "LogFile.hpp" 00041 00042 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00043 MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::MutableVertexMesh(std::vector<Node<SPACE_DIM>*> nodes, 00044 std::vector<VertexElement<ELEMENT_DIM,SPACE_DIM>*> vertexElements, 00045 double cellRearrangementThreshold, 00046 double t2Threshold, 00047 double cellRearrangementRatio) 00048 : mCellRearrangementThreshold(cellRearrangementThreshold), 00049 mCellRearrangementRatio(cellRearrangementRatio), 00050 mT2Threshold(t2Threshold), 00051 mCheckForInternalIntersections(false) 00052 { 00053 assert(cellRearrangementThreshold > 0.0); 00054 assert(t2Threshold > 0.0); 00055 00056 // Reset member variables and clear mNodes and mElements 00057 Clear(); 00058 00059 // Populate mNodes and mElements 00060 for (unsigned node_index=0; node_index<nodes.size(); node_index++) 00061 { 00062 Node<SPACE_DIM>* p_temp_node = nodes[node_index]; 00063 this->mNodes.push_back(p_temp_node); 00064 } 00065 for (unsigned elem_index=0; elem_index<vertexElements.size(); elem_index++) 00066 { 00067 VertexElement<ELEMENT_DIM,SPACE_DIM>* p_temp_vertex_element = vertexElements[elem_index]; 00068 this->mElements.push_back(p_temp_vertex_element); 00069 } 00070 // In 3D, populate mFaces 00071 if (SPACE_DIM == 3) 00072 { 00073 // Use a std::set to keep track of which faces have been added to mFaces 00074 std::set<unsigned> faces_counted; 00075 00076 // Loop over mElements 00077 for (unsigned elem_index=0; elem_index<this->mElements.size(); elem_index++) 00078 { 00079 // Loop over faces of this element 00080 for (unsigned face_index=0; face_index<this->mElements[elem_index]->GetNumFaces(); face_index++) 00081 { 00082 VertexElement<ELEMENT_DIM-1, SPACE_DIM>* p_face = this->mElements[elem_index]->GetFace(face_index); 00083 00084 // If this face is not already contained in mFaces, add it, and update faces_counted 00085 if (faces_counted.find(p_face->GetIndex()) == faces_counted.end()) 00086 { 00087 this->mFaces.push_back(p_face); 00088 faces_counted.insert(p_face->GetIndex()); 00089 } 00090 } 00091 } 00092 } 00093 00094 // Register elements with nodes 00095 for (unsigned index=0; index<this->mElements.size(); index++) 00096 { 00097 VertexElement<ELEMENT_DIM,SPACE_DIM>* p_temp_vertex_element = this->mElements[index]; 00098 for (unsigned node_index=0; node_index<p_temp_vertex_element->GetNumNodes(); node_index++) 00099 { 00100 Node<SPACE_DIM>* p_temp_node = p_temp_vertex_element->GetNode(node_index); 00101 p_temp_node->AddElement(p_temp_vertex_element->GetIndex()); 00102 } 00103 } 00104 00105 this->mMeshChangesDuringSimulation = true; 00106 } 00107 00108 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00109 MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::MutableVertexMesh() 00110 : mCellRearrangementThreshold(0.01), // Overwritten as soon as archiving is complete 00111 mCellRearrangementRatio(1.5), // Overwritten as soon as archiving is complete 00112 mT2Threshold(0.001), // Overwritten as soon as archiving is complete 00113 mCheckForInternalIntersections(false) // Overwritten as soon as archiving is complete 00114 { 00115 this->mMeshChangesDuringSimulation = true; 00116 Clear(); 00117 } 00118 00119 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00120 MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::~MutableVertexMesh() 00121 { 00122 Clear(); 00123 } 00124 00125 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00126 double MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetCellRearrangementThreshold() const 00127 { 00128 return mCellRearrangementThreshold; 00129 } 00130 00131 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00132 double MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetT2Threshold() const 00133 { 00134 return mT2Threshold; 00135 } 00136 00137 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00138 double MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetCellRearrangementRatio() const 00139 { 00140 return mCellRearrangementRatio; 00141 } 00142 00143 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00144 bool MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetCheckForInternalIntersections() const 00145 { 00146 return mCheckForInternalIntersections; 00147 } 00148 00149 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00150 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::SetCellRearrangementThreshold(double cellRearrangementThreshold) 00151 { 00152 mCellRearrangementThreshold = cellRearrangementThreshold; 00153 } 00154 00155 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00156 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::SetT2Threshold(double t2Threshold) 00157 { 00158 mT2Threshold = t2Threshold; 00159 } 00160 00161 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00162 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::SetCellRearrangementRatio(double cellRearrangementRatio) 00163 { 00164 mCellRearrangementRatio = cellRearrangementRatio; 00165 } 00166 00167 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00168 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::SetCheckForInternalIntersections(bool checkForInternalIntersections) 00169 { 00170 mCheckForInternalIntersections=checkForInternalIntersections; 00171 } 00172 00173 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00174 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::Clear() 00175 { 00176 mDeletedNodeIndices.clear(); 00177 mDeletedElementIndices.clear(); 00178 00179 VertexMesh<ELEMENT_DIM, SPACE_DIM>::Clear(); 00180 } 00181 00182 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00183 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNumNodes() const 00184 { 00185 return this->mNodes.size() - mDeletedNodeIndices.size(); 00186 } 00187 00188 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00189 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetNumElements() const 00190 { 00191 return this->mElements.size() - mDeletedElementIndices.size(); 00192 } 00193 00194 //\todo deal with boundary elements in vertex meshes #1392. 00195 //template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00196 //unsigned AbstractTetrahedralMesh<ELEMENT_DIM, SPACE_DIM>::GetNumBoundaryElements() const 00197 //{ 00198 // return mBoundaryElements.size(); 00199 //} 00200 00201 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00202 std::vector< c_vector<double, SPACE_DIM> > MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetLocationsOfT1Swaps() 00203 { 00204 return mLocationsOfT1Swaps; 00205 } 00206 00207 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00208 std::vector< c_vector<double, SPACE_DIM> > MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::GetLocationsOfT3Swaps() 00209 { 00210 return mLocationsOfT3Swaps; 00211 } 00212 00213 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00214 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::ClearLocationsOfT1Swaps() 00215 { 00216 mLocationsOfT1Swaps.clear(); 00217 } 00218 00219 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00220 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::ClearLocationsOfT3Swaps() 00221 { 00222 mLocationsOfT3Swaps.clear(); 00223 } 00224 00225 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00226 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::AddNode(Node<SPACE_DIM>* pNewNode) 00227 { 00228 if (mDeletedNodeIndices.empty()) 00229 { 00230 pNewNode->SetIndex(this->mNodes.size()); 00231 this->mNodes.push_back(pNewNode); 00232 } 00233 else 00234 { 00235 unsigned index = mDeletedNodeIndices.back(); 00236 pNewNode->SetIndex(index); 00237 mDeletedNodeIndices.pop_back(); 00238 delete this->mNodes[index]; 00239 this->mNodes[index] = pNewNode; 00240 } 00241 return pNewNode->GetIndex(); 00242 } 00243 00244 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00245 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::AddElement(VertexElement<ELEMENT_DIM,SPACE_DIM>* pNewElement) 00246 { 00247 unsigned new_element_index = pNewElement->GetIndex(); 00248 00249 if (new_element_index == this->mElements.size()) 00250 { 00251 this->mElements.push_back(pNewElement); 00252 } 00253 else 00254 { 00255 this->mElements[new_element_index] = pNewElement; 00256 } 00257 pNewElement->RegisterWithNodes(); 00258 return pNewElement->GetIndex(); 00259 } 00260 00261 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00262 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::SetNode(unsigned nodeIndex, ChastePoint<SPACE_DIM> point) 00263 { 00264 this->mNodes[nodeIndex]->SetPoint(point); 00265 } 00266 00267 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00268 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::DivideElementAlongGivenAxis(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, 00269 c_vector<double, SPACE_DIM> axisOfDivision, 00270 bool placeOriginalElementBelow) 00271 { 00272 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 00273 assert(SPACE_DIM == 2); // only works in 2D at present 00274 assert(ELEMENT_DIM == SPACE_DIM); 00275 00276 // Get the centroid of the element 00277 c_vector<double, SPACE_DIM> centroid = this->GetCentroidOfElement(pElement->GetIndex()); 00278 00279 // Create a vector perpendicular to the axis of division 00280 c_vector<double, SPACE_DIM> perp_axis; 00281 perp_axis(0) = -axisOfDivision(1); 00282 perp_axis(1) = axisOfDivision(0); 00283 00284 /* 00285 * Find which edges the axis of division crosses by finding any node 00286 * that lies on the opposite side of the axis of division to its next 00287 * neighbour. 00288 */ 00289 unsigned num_nodes = pElement->GetNumNodes(); 00290 std::vector<unsigned> intersecting_nodes; 00291 for (unsigned i=0; i<num_nodes; i++) 00292 { 00293 bool is_current_node_on_left = (inner_prod(this->GetVectorFromAtoB(pElement->GetNodeLocation(i), centroid), perp_axis) >= 0); 00294 bool is_next_node_on_left = (inner_prod(this->GetVectorFromAtoB(pElement->GetNodeLocation((i+1)%num_nodes), centroid), perp_axis) >= 0); 00295 00296 if (is_current_node_on_left != is_next_node_on_left) 00297 { 00298 intersecting_nodes.push_back(i); 00299 } 00300 } 00301 00302 // If the axis of division does not cross two edges then we cannot proceed 00303 if (intersecting_nodes.size() != 2) 00304 { 00305 EXCEPTION("Cannot proceed with element division: the given axis of division does not cross two edges of the element"); 00306 } 00307 00308 std::vector<unsigned> division_node_global_indices; 00309 unsigned nodes_added = 0; 00310 00311 // Find the intersections between the axis of division and the element edges 00312 for (unsigned i=0; i<intersecting_nodes.size(); i++) 00313 { 00314 /* 00315 * Get pointers to the nodes forming the edge into which one new node will be inserted. 00316 * 00317 * Note that when we use the first entry of intersecting_nodes to add a node, 00318 * we change the local index of the second entry of intersecting_nodes in 00319 * pElement, so must account for this by moving one entry further on. 00320 */ 00321 Node<SPACE_DIM>* p_node_A = pElement->GetNode((intersecting_nodes[i]+nodes_added)%pElement->GetNumNodes()); 00322 Node<SPACE_DIM>* p_node_B = pElement->GetNode((intersecting_nodes[i]+nodes_added+1)%pElement->GetNumNodes()); 00323 00324 // Find the indices of the elements owned by each node on the edge into which one new node will be inserted 00325 std::set<unsigned> elems_containing_node_A = p_node_A->rGetContainingElementIndices(); 00326 std::set<unsigned> elems_containing_node_B = p_node_B->rGetContainingElementIndices(); 00327 00328 c_vector<double, SPACE_DIM> position_a = p_node_A->rGetLocation(); 00329 c_vector<double, SPACE_DIM> position_b = p_node_B->rGetLocation(); 00330 c_vector<double, SPACE_DIM> a_to_b = this->GetVectorFromAtoB(position_a, position_b); 00331 00332 c_vector<double, SPACE_DIM> intersection; 00333 00334 if (norm_2(a_to_b) < 2.0*mCellRearrangementRatio*mCellRearrangementThreshold) 00335 { 00336 WARNING("Edge is too small for normal division, putting node in the middle of a and b, there may be T1Swaps straight away."); 00338 intersection = position_a + 0.5*a_to_b; 00339 } 00340 else 00341 { 00342 // Find the location of the intersection 00343 double determinant = a_to_b[0]*axisOfDivision[1] - a_to_b[1]*axisOfDivision[0]; 00344 00345 c_vector<double, SPACE_DIM> moved_centroid = position_a + this->GetVectorFromAtoB(position_a, centroid); // allow for periodicity and other metrics 00346 00347 double alpha = (moved_centroid[0]*a_to_b[1] - position_a[0]*a_to_b[1] 00348 -moved_centroid[1]*a_to_b[0] + position_a[1]*a_to_b[0])/determinant; 00349 00350 intersection = moved_centroid + alpha*axisOfDivision; 00351 00352 /* 00353 * If then new node is too close to one of the edge nodes, then reposition it 00354 * a distance mCellRearrangementRatio*mCellRearrangementThreshold further along the edge. 00355 */ 00356 c_vector<double, SPACE_DIM> a_to_intersection = this->GetVectorFromAtoB(position_a, intersection); 00357 if (norm_2(a_to_intersection) < mCellRearrangementThreshold) 00358 { 00359 intersection = position_a + mCellRearrangementRatio*mCellRearrangementThreshold*a_to_b/norm_2(a_to_b); 00360 } 00361 00362 c_vector<double, SPACE_DIM> b_to_intersection = this->GetVectorFromAtoB(position_b, intersection); 00363 if (norm_2(b_to_intersection) < mCellRearrangementThreshold) 00364 { 00365 assert(norm_2(a_to_intersection) > mCellRearrangementThreshold); // to prevent moving intersection back to original position 00366 00367 intersection = position_b - mCellRearrangementRatio*mCellRearrangementThreshold*a_to_b/norm_2(a_to_b); 00368 } 00369 } 00370 00371 /* 00372 * The new node is boundary node if the 2 nodes are boundary nodes and the elements don't look like 00373 * ___A___ 00374 * | | | 00375 * |___|___| 00376 * B 00377 */ 00378 00379 bool is_boundary = false; 00380 if (p_node_A->IsBoundaryNode() && p_node_B->IsBoundaryNode()) 00381 { 00382 if (elems_containing_node_A.size() !=2 || 00383 elems_containing_node_B.size() !=2 || 00384 elems_containing_node_A != elems_containing_node_B) 00385 { 00386 is_boundary = true; 00387 } 00388 } 00389 00390 // Add a new node to the mesh at the location of the intersection 00391 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, is_boundary, intersection[0], intersection[1])); 00392 nodes_added++; 00393 00394 // Now make sure node is added to neighbouring elements 00395 00396 // Find common elements 00397 std::set<unsigned> shared_elements; 00398 std::set_intersection(elems_containing_node_A.begin(), 00399 elems_containing_node_A.end(), 00400 elems_containing_node_B.begin(), 00401 elems_containing_node_B.end(), 00402 std::inserter(shared_elements, shared_elements.begin())); 00403 00404 // Iterate over common elements 00405 for (std::set<unsigned>::iterator iter = shared_elements.begin(); 00406 iter != shared_elements.end(); 00407 ++iter) 00408 { 00409 // Find which node has the lower local index in this element 00410 unsigned local_indexA = this->GetElement(*iter)->GetNodeLocalIndex(p_node_A->GetIndex()); 00411 unsigned local_indexB = this->GetElement(*iter)->GetNodeLocalIndex(p_node_B->GetIndex()); 00412 00413 unsigned index = local_indexB; 00414 if (local_indexB > local_indexA) 00415 { 00416 index = local_indexA; 00417 } 00418 if ((local_indexA == 0) && (local_indexB == this->GetElement(*iter)->GetNumNodes()-1)) 00419 { 00420 index = local_indexB; 00421 } 00422 if ((local_indexB == 0) && (local_indexA == this->GetElement(*iter)->GetNumNodes()-1)) 00423 { 00424 index = local_indexA; 00425 } 00426 // Add new node to this element 00427 this->GetElement(*iter)->AddNode(this->GetNode(new_node_global_index), index); 00428 } 00429 // Store index of new node 00430 division_node_global_indices.push_back(new_node_global_index); 00431 } 00432 00433 // Now call DivideElement() to divide the element using the new nodes 00434 unsigned new_element_index = DivideElement(pElement, 00435 pElement->GetNodeLocalIndex(division_node_global_indices[0]), 00436 pElement->GetNodeLocalIndex(division_node_global_indices[1]), 00437 placeOriginalElementBelow); 00438 return new_element_index; 00439 } 00440 00441 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00442 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::DivideElementAlongShortAxis(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, 00443 bool placeOriginalElementBelow) 00444 { 00445 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 00446 assert(SPACE_DIM == 2); // only works in 2D at present 00447 assert(ELEMENT_DIM == SPACE_DIM); 00448 00449 // Find the short axis of the element 00450 c_vector<double, SPACE_DIM> short_axis = this->GetShortAxisOfElement(pElement->GetIndex()); 00451 00452 unsigned new_element_index = DivideElementAlongGivenAxis(pElement, short_axis, placeOriginalElementBelow); 00453 return new_element_index; 00454 } 00455 00456 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00457 unsigned MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::DivideElement(VertexElement<ELEMENT_DIM,SPACE_DIM>* pElement, 00458 unsigned nodeAIndex, 00459 unsigned nodeBIndex, 00460 bool placeOriginalElementBelow) 00461 { 00462 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 00463 assert(SPACE_DIM == 2); // only works in 2D at present 00464 assert(ELEMENT_DIM == SPACE_DIM); 00465 00466 // Sort nodeA and nodeB such that nodeBIndex > nodeAindex 00467 assert(nodeBIndex != nodeAIndex); 00468 00469 unsigned node1_index = (nodeAIndex < nodeBIndex) ? nodeAIndex : nodeBIndex; // low index 00470 unsigned node2_index = (nodeAIndex < nodeBIndex) ? nodeBIndex : nodeAIndex; // high index 00471 00472 // Store the number of nodes in the element (this changes when nodes are deleted from the element) 00473 unsigned num_nodes = pElement->GetNumNodes(); 00474 00475 // Copy the nodes in this element 00476 std::vector<Node<SPACE_DIM>*> nodes_elem; 00477 for (unsigned i=0; i<num_nodes; i++) 00478 { 00479 nodes_elem.push_back(pElement->GetNode(i)); 00480 } 00481 00482 // Get the index of the new element 00483 unsigned new_element_index; 00484 if (mDeletedElementIndices.empty()) 00485 { 00486 new_element_index = this->mElements.size(); 00487 } 00488 else 00489 { 00490 new_element_index = mDeletedElementIndices.back(); 00491 mDeletedElementIndices.pop_back(); 00492 delete this->mElements[new_element_index]; 00493 } 00494 00495 // Add the new element to the mesh 00496 AddElement(new VertexElement<ELEMENT_DIM,SPACE_DIM>(new_element_index, nodes_elem)); 00497 00504 // Find lowest element 00506 double height_midpoint_1 = 0.0; 00507 double height_midpoint_2 = 0.0; 00508 unsigned counter_1 = 0; 00509 unsigned counter_2 = 0; 00510 00511 for (unsigned i=0; i<num_nodes; i++) 00512 { 00513 if (i>=node1_index && i<=node2_index) 00514 { 00515 height_midpoint_1 += pElement->GetNode(i)->rGetLocation()[1]; 00516 counter_1++; 00517 } 00518 if (i<=node1_index || i>=node2_index) 00519 { 00520 height_midpoint_2 += pElement->GetNode(i)->rGetLocation()[1]; 00521 counter_2++; 00522 } 00523 } 00524 height_midpoint_1 /= (double)counter_1; 00525 height_midpoint_2 /= (double)counter_2; 00526 00527 for (unsigned i=num_nodes; i>0; i--) 00528 { 00529 if (i-1 < node1_index || i-1 > node2_index) 00530 { 00531 if (height_midpoint_1 < height_midpoint_2) 00532 { 00533 if (placeOriginalElementBelow) 00534 { 00535 pElement->DeleteNode(i-1); 00536 } 00537 else 00538 { 00539 this->mElements[new_element_index]->DeleteNode(i-1); 00540 } 00541 } 00542 else 00543 { 00544 if (placeOriginalElementBelow) 00545 { 00546 this->mElements[new_element_index]->DeleteNode(i-1); 00547 } 00548 else 00549 { 00550 pElement->DeleteNode(i-1); 00551 } 00552 } 00553 } 00554 else if (i-1 > node1_index && i-1 < node2_index) 00555 { 00556 if (height_midpoint_1 < height_midpoint_2) 00557 { 00558 if (placeOriginalElementBelow) 00559 { 00560 this->mElements[new_element_index]->DeleteNode(i-1); 00561 } 00562 else 00563 { 00564 pElement->DeleteNode(i-1); 00565 } 00566 } 00567 else 00568 { 00569 if (placeOriginalElementBelow) 00570 { 00571 pElement->DeleteNode(i-1); 00572 } 00573 else 00574 { 00575 this->mElements[new_element_index]->DeleteNode(i-1); 00576 } 00577 } 00578 } 00579 } 00580 00581 return new_element_index; 00582 } 00583 00584 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00585 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::DeleteElementPriorToReMesh(unsigned index) 00586 { 00587 assert(SPACE_DIM == 2); 00588 00589 // Mark any nodes that are contained only in this element as deleted 00590 for (unsigned i=0; i<this->mElements[index]->GetNumNodes(); i++) 00591 { 00592 Node<SPACE_DIM>* p_node = this->mElements[index]->GetNode(i); 00593 00594 if (p_node->rGetContainingElementIndices().size()==1) 00595 { 00596 DeleteNodePriorToReMesh(p_node->GetIndex()); 00597 } 00598 00599 // Mark all the nodes contained in the removed element as boundary nodes 00600 p_node->SetAsBoundaryNode(true); 00601 } 00602 00603 // Mark this element as deleted 00604 this->mElements[index]->MarkAsDeleted(); 00605 mDeletedElementIndices.push_back(index); 00606 } 00607 00608 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00609 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::DeleteNodePriorToReMesh(unsigned index) 00610 { 00611 this->mNodes[index]->MarkAsDeleted(); 00612 mDeletedNodeIndices.push_back(index); 00613 } 00614 00615 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00616 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::DivideEdge(Node<SPACE_DIM>* pNodeA, Node<SPACE_DIM>* pNodeB) 00617 { 00618 // Find the indices of the elements owned by each node 00619 std::set<unsigned> elements_containing_nodeA = pNodeA->rGetContainingElementIndices(); 00620 std::set<unsigned> elements_containing_nodeB = pNodeB->rGetContainingElementIndices(); 00621 00622 // Find common elements 00623 std::set<unsigned> shared_elements; 00624 std::set_intersection(elements_containing_nodeA.begin(), 00625 elements_containing_nodeA.end(), 00626 elements_containing_nodeB.begin(), 00627 elements_containing_nodeB.end(), 00628 std::inserter(shared_elements, shared_elements.begin())); 00629 00630 // Check that the nodes have a common edge and not more than 2 00631 assert(!shared_elements.empty()); 00632 assert(!shared_elements.size()<=2); 00633 00634 // Specifiy if its a boundary node 00635 bool is_boundary_node = false; 00636 if (shared_elements.size()==1) 00637 { 00638 // If only one shared element then must be on the boundary. 00639 assert((pNodeA->IsBoundaryNode())&&(pNodeB->IsBoundaryNode())); 00640 is_boundary_node = true; 00641 } 00642 00643 // Create a new node (position is not important as it will be changed) 00644 Node<SPACE_DIM>* p_new_node = new Node<SPACE_DIM>(GetNumNodes(), is_boundary_node, 0.0, 0.0); 00645 00646 // Update the node location 00647 c_vector<double, SPACE_DIM> new_node_position = pNodeA->rGetLocation() + 0.5*this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeB->rGetLocation()); 00648 ChastePoint<SPACE_DIM> point(new_node_position); 00649 p_new_node->SetPoint(new_node_position); 00650 00651 // Add node to mesh 00652 this->mNodes.push_back(p_new_node); 00653 00654 // Iterate over common elements 00655 for (std::set<unsigned>::iterator iter = shared_elements.begin(); 00656 iter != shared_elements.end(); 00657 ++iter) 00658 { 00659 // Find which node has the lower local index in this element 00660 unsigned local_indexA = this->GetElement(*iter)->GetNodeLocalIndex(pNodeA->GetIndex()); 00661 unsigned local_indexB = this->GetElement(*iter)->GetNodeLocalIndex(pNodeB->GetIndex()); 00662 00663 unsigned index = local_indexB; 00664 if ( local_indexB > local_indexA ) 00665 { 00666 index = local_indexA; 00667 } 00668 if ( (local_indexA == 0) && (local_indexB == this->GetElement(*iter)->GetNumNodes()-1)) 00669 { 00670 index = local_indexB; 00671 } 00672 if ( (local_indexB == 0) && (local_indexA == this->GetElement(*iter)->GetNumNodes()-1)) 00673 { 00674 index = local_indexA; 00675 } 00676 // Add new node to this element 00677 this->GetElement(*iter)->AddNode(p_new_node, index); 00678 } 00679 } 00680 00681 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00682 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::RemoveDeletedNodesAndElements(VertexElementMap& rElementMap) 00683 { 00684 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 00685 assert(SPACE_DIM==2 || SPACE_DIM==3); 00686 assert(ELEMENT_DIM == SPACE_DIM); 00687 00688 // Make sure the map is big enough 00689 rElementMap.Resize(this->GetNumAllElements()); 00690 00691 // Remove deleted elements 00692 std::vector<VertexElement<ELEMENT_DIM, SPACE_DIM>*> live_elements; 00693 for (unsigned i=0; i< this->mElements.size(); i++) 00694 { 00695 if (this->mElements[i]->IsDeleted()) 00696 { 00697 delete this->mElements[i]; 00698 rElementMap.SetDeleted(i); 00699 } 00700 else 00701 { 00702 live_elements.push_back(this->mElements[i]); 00703 rElementMap.SetNewIndex(i, (unsigned)(live_elements.size()-1)); 00704 } 00705 } 00706 00707 assert(mDeletedElementIndices.size() == this->mElements.size() - live_elements.size()); 00708 mDeletedElementIndices.clear(); 00709 this->mElements = live_elements; 00710 00711 for (unsigned i=0; i<this->mElements.size(); i++) 00712 { 00713 this->mElements[i]->ResetIndex(i); 00714 } 00715 00716 // Remove deleted nodes 00717 RemoveDeletedNodes(); 00718 } 00719 00720 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00721 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::RemoveDeletedNodes() 00722 { 00723 std::vector<Node<SPACE_DIM>*> live_nodes; 00724 for (unsigned i=0; i<this->mNodes.size(); i++) 00725 { 00726 if (this->mNodes[i]->IsDeleted()) 00727 { 00728 delete this->mNodes[i]; 00729 } 00730 else 00731 { 00732 live_nodes.push_back(this->mNodes[i]); 00733 } 00734 } 00735 00736 assert(mDeletedNodeIndices.size() == this->mNodes.size() - live_nodes.size()); 00737 this->mNodes = live_nodes; 00738 mDeletedNodeIndices.clear(); 00739 00740 for (unsigned i=0; i<this->mNodes.size(); i++) 00741 { 00742 this->mNodes[i]->SetIndex(i); 00743 } 00744 } 00745 00746 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00747 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::ReMesh(VertexElementMap& rElementMap) 00748 { 00749 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 00750 assert(SPACE_DIM==2 || SPACE_DIM==3); 00751 assert(ELEMENT_DIM == SPACE_DIM); 00752 00753 if (SPACE_DIM==2) 00754 { 00755 /* 00756 * We do not need to call Clear() and remove all current data, since 00757 * cell birth, rearrangement and death result only in local remeshing 00758 * of a vertex-based mesh. 00759 */ 00760 00761 // Remove deleted nodes and elements 00762 RemoveDeletedNodesAndElements(rElementMap); 00763 00764 // Check for element rearrangements 00765 bool recheck_mesh = true; 00766 while (recheck_mesh == true) 00767 { 00768 // Separate loops as need to check for T2Swaps first 00769 recheck_mesh = CheckForT2Swaps(rElementMap); 00770 00771 if (recheck_mesh == false) 00772 { 00773 recheck_mesh = CheckForT1Swaps(rElementMap); 00774 } 00775 } 00776 00777 //Check for element intersections. 00778 recheck_mesh = true; 00779 while (recheck_mesh == true) 00780 { 00781 //Check mesh for intersections, and perform T3Swaps where required 00782 recheck_mesh = CheckForIntersections(); 00783 } 00784 00785 RemoveDeletedNodes(); // to remove any nodes if they are deleted 00786 } 00787 else // 3D 00788 { 00789 #define COVERAGE_IGNORE 00790 EXCEPTION("Remeshing has not been implemented in 3D (see #827 and #860)\n"); 00791 #undef COVERAGE_IGNORE 00792 00793 } 00794 } 00795 00796 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00797 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::ReMesh() 00798 { 00799 VertexElementMap map(GetNumElements()); 00800 ReMesh(map); 00801 } 00802 00803 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00804 bool MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::CheckForT1Swaps(VertexElementMap& rElementMap) 00805 { 00806 // Loop over elements to check for T1Swaps 00807 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = this->GetElementIteratorBegin(); 00808 elem_iter != this->GetElementIteratorEnd(); 00809 ++elem_iter) 00810 { 00811 unsigned num_nodes = elem_iter->GetNumNodes(); 00812 assert(num_nodes > 0); // if not element should be deleted 00813 00814 unsigned new_num_nodes = num_nodes; 00815 00816 /* 00817 * Perform T1 swaps and merges where necessary 00818 * Check there are > 3 nodes in both elements that contain the pair of nodes 00819 * and the edges are small enough 00820 */ 00821 00822 // Loop over element vertices 00823 for (unsigned local_index=0; local_index<num_nodes; local_index++) 00824 { 00825 // Find locations of current node and anticlockwise node 00826 Node<SPACE_DIM>* p_current_node = elem_iter->GetNode(local_index); 00827 unsigned local_index_plus_one = (local_index+1)%new_num_nodes; 00828 Node<SPACE_DIM>* p_anticlockwise_node = elem_iter->GetNode(local_index_plus_one); 00829 00830 // Find distance between nodes 00831 double distance_between_nodes = this->GetDistanceBetweenNodes(p_current_node->GetIndex(), p_anticlockwise_node->GetIndex()); 00832 00833 std::set<unsigned> elements_of_node_a = p_current_node->rGetContainingElementIndices(); 00834 std::set<unsigned> elements_of_node_b = p_anticlockwise_node->rGetContainingElementIndices(); 00835 00836 std::set<unsigned> all_elements; 00837 std::set_union(elements_of_node_a.begin(), elements_of_node_a.end(), 00838 elements_of_node_b.begin(), elements_of_node_b.end(), 00839 std::inserter(all_elements, all_elements.begin())); 00840 00841 // Track if either node is in a triangular element. 00842 bool triangular_element = false; 00843 00844 for (std::set<unsigned>::const_iterator it = all_elements.begin(); 00845 it != all_elements.end(); 00846 ++it) 00847 { 00848 if (this->GetElement(*it)->GetNumNodes() <= 3) 00849 { 00850 triangular_element = true; 00851 } 00852 } 00853 00854 // If the nodes are too close together and we don't have any triangular elements connected to the nodes, perform a swap 00855 if ((!triangular_element) && (distance_between_nodes < mCellRearrangementThreshold)) 00856 { 00857 // Identify the type of node swap/merge needed then call method to perform swap/merge 00858 IdentifySwapType(p_current_node, p_anticlockwise_node, rElementMap); 00859 return true; 00860 } 00861 } 00862 } 00863 return false; 00864 } 00865 00866 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00867 bool MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::CheckForT2Swaps(VertexElementMap& rElementMap) 00868 { 00869 00870 // Loop over elements to check for T2Swaps 00871 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = this->GetElementIteratorBegin(); 00872 elem_iter != this->GetElementIteratorEnd(); 00873 ++elem_iter) 00874 { 00875 if (elem_iter->GetNumNodes() == 3u) 00876 { 00877 /* 00878 * Perform T2 swaps where necessary 00879 * Check there are only 3 nodes and the element is small enough 00880 */ 00881 if (this->GetVolumeOfElement(elem_iter->GetIndex()) < GetT2Threshold()) 00882 { 00883 PerformT2Swap(*elem_iter); 00884 00885 // Now remove the deleted nodes (if we don't do this then the search for T1Swap causes errors) 00886 RemoveDeletedNodesAndElements(rElementMap); 00887 00888 return true; 00889 } 00890 } 00891 } 00892 return false; 00893 } 00894 00895 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00896 bool MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::CheckForIntersections() 00897 { 00898 // Check that no boundary nodes have overlapped elements on the boundary 00899 for (typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator node_iter = this->GetNodeIteratorBegin(); 00900 node_iter != this->GetNodeIteratorEnd(); 00901 ++node_iter) 00902 { 00903 if (node_iter->IsBoundaryNode()) 00904 { 00905 assert(!(node_iter->IsDeleted())); 00906 00907 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = this->GetElementIteratorBegin(); 00908 elem_iter != this->GetElementIteratorEnd(); 00909 ++elem_iter) 00910 { 00911 if (elem_iter->IsElementOnBoundary()) 00912 { 00913 00914 unsigned elem_index = elem_iter->GetIndex(); 00915 00916 // Check that the node is not part of this element. 00917 if (node_iter->rGetContainingElementIndices().count(elem_index) == 0) 00918 { 00919 if (this->ElementIncludesPoint(node_iter->rGetLocation(), elem_index)) 00920 { 00921 PerformT3Swap(&(*node_iter), elem_index); 00922 return true; 00923 } 00924 } 00925 } 00926 } 00927 } 00928 } 00929 00930 if (mCheckForInternalIntersections) 00931 { 00932 // Check that no nodes have overlapped elements inside the mesh // Change to only loop over neighboring elements 00933 for (typename AbstractMesh<ELEMENT_DIM,SPACE_DIM>::NodeIterator node_iter = this->GetNodeIteratorBegin(); 00934 node_iter != this->GetNodeIteratorEnd(); 00935 ++node_iter) 00936 { 00937 assert(!(node_iter->IsDeleted())); 00938 00939 for (typename VertexMesh<ELEMENT_DIM, SPACE_DIM>::VertexElementIterator elem_iter = this->GetElementIteratorBegin(); 00940 elem_iter != this->GetElementIteratorEnd(); 00941 ++elem_iter) 00942 { 00943 unsigned elem_index = elem_iter->GetIndex(); 00944 00945 // Check that the node is not part of this element. 00946 if (node_iter->rGetContainingElementIndices().count(elem_index) == 0) 00947 { 00948 if (this->ElementIncludesPoint(node_iter->rGetLocation(), elem_index)) 00949 { 00950 PerformIntersectionSwap(&(*node_iter), elem_index); 00951 return true; 00952 } 00953 } 00954 } 00955 } 00956 } 00957 00958 return false; 00959 } 00960 00961 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 00962 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::IdentifySwapType(Node<SPACE_DIM>* pNodeA, Node<SPACE_DIM>* pNodeB, VertexElementMap& rElementMap) 00963 { 00964 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 00965 assert(SPACE_DIM == 2); // this method only works in 2D at present 00966 assert(ELEMENT_DIM == SPACE_DIM); 00967 00968 // Find the sets of elements containing nodes A and B 00969 std::set<unsigned> nodeA_elem_indices = pNodeA->rGetContainingElementIndices(); 00970 00971 std::set<unsigned> nodeB_elem_indices = pNodeB->rGetContainingElementIndices(); 00972 00973 // Form the set union 00974 std::set<unsigned> all_indices, temp_set; 00975 std::set_union(nodeA_elem_indices.begin(), nodeA_elem_indices.end(), 00976 nodeB_elem_indices.begin(), nodeB_elem_indices.end(), 00977 std::inserter(temp_set, temp_set.begin())); 00978 all_indices.swap(temp_set); // temp_set will be deleted 00979 00980 if ((nodeA_elem_indices.size()>3) || (nodeB_elem_indices.size()>3)) 00981 { 00982 /* 00983 * Looks like 00984 * 00985 * \ 00986 * \ A B 00987 * ---o---o--- 00988 * / 00989 * / 00990 * 00991 */ 00992 EXCEPTION("A node is contained in more than three elements"); // the code can't handle this case 00993 } 00994 else // each node is contained in at most three elements 00995 { 00996 switch (all_indices.size()) 00997 { 00998 case 1: 00999 { 01000 /* 01001 * In this case, each node is contained in a single element, so the nodes 01002 * lie on the boundary of the mesh: 01003 * 01004 * A B 01005 * ---o---o--- 01006 * 01007 * We merge the nodes. 01008 */ 01009 01010 // Check nodes A and B are on the boundary 01011 assert(pNodeA->IsBoundaryNode()); 01012 assert(pNodeB->IsBoundaryNode()); 01013 01014 PerformNodeMerge(pNodeA, pNodeB); 01015 01016 // Remove the deleted node and re-index 01017 RemoveDeletedNodes(); 01018 break; 01019 } 01020 case 2: 01021 { 01022 if (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==2) 01023 { 01024 if (pNodeA->IsBoundaryNode() && pNodeB->IsBoundaryNode()) 01025 { 01026 /* 01027 * In this case, the node configuration looks like: 01028 * 01029 * \ / 01030 * \ / Node A 01031 * (1) | (2) (element number in brackets) 01032 * / \ Node B 01033 * / \ 01034 * 01035 * With voids on top and bottom 01036 * 01037 * We perform a Type 1 swap and separate the elements in this case. 01038 */ 01039 PerformT1Swap(pNodeA, pNodeB,all_indices); 01040 } 01041 else if (pNodeA->IsBoundaryNode() || pNodeB->IsBoundaryNode()) 01042 { 01043 /* 01044 * In this case, the node configuration looks like: 01045 * 01046 * \ / 01047 * \ / Node A 01048 * (1) | (2) (element number in brackets) 01049 * x Node B 01050 * | 01051 * 01052 * With a void on top. 01053 * 01054 * We should not be able to get here when running normal vertex code 01055 * as there should only be nodes on 3 way junctions or boundaries. 01056 * 01057 */ 01058 01059 EXCEPTION("There is a non boundary node contained only in 2 elements something has gone wrong."); 01060 } 01061 else 01062 { 01063 /* 01064 * In this case, each node is contained in two elements, so the nodes 01065 * lie on an internal edge: 01066 * 01067 * A B 01068 * ---o---o--- 01069 * 01070 * We should not be able to get here when running normal vertex code 01071 * as there should only be nodes on 3 way junctions or boundaries. 01072 */ 01073 01074 EXCEPTION("There are non-boundary nodes contained in only in 2 elements something has gone wrong."); 01075 } 01076 } 01077 else 01078 { 01079 /* 01080 * In this case, the node configuration looks like: 01081 * 01082 * Outside 01083 * / 01084 * --o--o (2) 01085 * (1) \ 01086 * 01087 * We merge the nodes in this case. ///\todo this should be a T1 Swap see #1263 01088 */ 01089 01090 PerformNodeMerge(pNodeA, pNodeB); 01091 01092 // Remove the deleted node and re-index 01093 RemoveDeletedNodes(); 01094 } 01095 break; 01096 } 01097 case 3: 01098 { 01099 if (nodeA_elem_indices.size()==1 || nodeB_elem_indices.size()==1) 01100 { 01101 /* 01102 * In this case, one node is contained in one element and 01103 * the other node is contained in three elements: 01104 * 01105 * A B 01106 * 01107 * empty / 01108 * / (3) 01109 * ---o---o----- (element number in brackets) 01110 * (1) \ (2) 01111 * \ 01112 * 01113 * We should not be able to get here when running normal vertex code 01114 * as a boundary node is contained in at most 2 elements. 01115 */ 01116 01117 // Check nodes A and B are on the boundary 01118 assert(pNodeA->IsBoundaryNode()); 01119 assert(pNodeB->IsBoundaryNode()); 01120 01121 EXCEPTION("There is a boundary node contained in three elements something has gone wrong."); 01122 } 01123 else if (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==2) 01124 { 01125 // element in nodeA_elem_indices which is not in nodeB_elem_indices contains a shared node with the element in nodeA_elem_indices which is not in nodeB_elem_indices. 01126 01127 std::set<unsigned> element_A_not_B, temp_set; 01128 std::set_difference(all_indices.begin(), all_indices.end(), 01129 nodeB_elem_indices.begin(), nodeB_elem_indices.end(), 01130 std::inserter(temp_set, temp_set.begin())); 01131 element_A_not_B.swap(temp_set); 01132 01133 // Should only be one such element 01134 assert(element_A_not_B.size()==1); 01135 01136 std::set<unsigned> element_B_not_A; 01137 std::set_difference(all_indices.begin(), all_indices.end(), 01138 nodeA_elem_indices.begin(), nodeA_elem_indices.end(), 01139 std::inserter(temp_set, temp_set.begin())); 01140 element_B_not_A.swap(temp_set); 01141 01142 // Should only be one such element 01143 assert(element_B_not_A.size()==1); 01144 01145 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_A_not_B = this->mElements[*element_A_not_B.begin()]; 01146 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_B_not_A = this->mElements[*element_B_not_A.begin()]; 01147 01148 unsigned local_index_1 = p_element_A_not_B->GetNodeLocalIndex(pNodeA->GetIndex()); 01149 unsigned next_node_1 = p_element_A_not_B->GetNodeGlobalIndex((local_index_1 + 1)%(p_element_A_not_B->GetNumNodes())); 01150 unsigned previous_node_1 = p_element_A_not_B->GetNodeGlobalIndex((local_index_1 + p_element_A_not_B->GetNumNodes() - 1)%(p_element_A_not_B->GetNumNodes())); 01151 unsigned local_index_2 = p_element_B_not_A->GetNodeLocalIndex(pNodeB->GetIndex()); 01152 unsigned next_node_2 = p_element_B_not_A->GetNodeGlobalIndex((local_index_2 + 1)%(p_element_B_not_A->GetNumNodes())); 01153 unsigned previous_node_2 = p_element_B_not_A->GetNodeGlobalIndex((local_index_2 + p_element_B_not_A->GetNumNodes() - 1)%(p_element_B_not_A->GetNumNodes())); 01154 01155 if (next_node_1 == previous_node_2 || next_node_2 == previous_node_1) 01156 { 01157 /* 01158 * In this case, the node configuration looks like: 01159 * 01160 * A C B A B 01161 * /\ \ / 01162 * /v \ \ (1) / 01163 * (3)o----o (1) or (2) o----o (3) (element number in brackets, v is a void) 01164 * / (2) \ \v / 01165 * / \ \/ 01166 * C 01167 * 01168 * We perform a T3 way merge, removing the void. 01169 */ 01170 01171 // Check nodes A and B are on the boundary 01172 assert(pNodeA->IsBoundaryNode()); 01173 assert(pNodeB->IsBoundaryNode()); 01174 01175 // Get the other node in the triangular void 01176 unsigned nodeC_index; 01177 if (next_node_1 == previous_node_2 && next_node_2 != previous_node_1) 01178 { 01179 nodeC_index = next_node_1; 01180 } 01181 else if (next_node_2 == previous_node_1 && next_node_1 != previous_node_2) 01182 { 01183 nodeC_index = next_node_2; 01184 } 01185 else 01186 { 01187 assert(next_node_1 == previous_node_2 && next_node_2 == previous_node_1); 01188 EXCEPTION("Triangular element next to triangular void, not implemented yet."); 01189 } 01190 01191 PerformVoidRemoval(pNodeA, pNodeB, this->mNodes[nodeC_index]); 01192 } 01193 else 01194 { 01195 /* 01196 * In this case, the node configuration looks like: 01197 * 01198 * A B A B 01199 * \ empty/ \ / 01200 * \ / \(1) / 01201 * (3) o--o (1) or (2) o--o (3) (element number in brackets) 01202 * / (2)\ / \ 01203 * / \ /empty \ 01204 * 01205 * We perform a T1 Swap in this case. 01206 */ 01207 01208 // Check nodes A and B are on the boundary 01209 assert(pNodeA->IsBoundaryNode()); 01210 assert(pNodeB->IsBoundaryNode()); 01211 01212 PerformT1Swap(pNodeA, pNodeB, all_indices); 01213 } 01214 } 01215 else 01216 { 01217 /* 01218 * In this case, one of the nodes is contained in two elements 01219 * and the other node is contained in three elements. 01220 */ 01221 assert ( (nodeA_elem_indices.size()==2 && nodeB_elem_indices.size()==3) 01222 || (nodeA_elem_indices.size()==3 && nodeB_elem_indices.size()==2) ); 01223 01224 // They can't both be boundary nodes 01225 assert(!(pNodeA->IsBoundaryNode() && pNodeB->IsBoundaryNode())); 01226 01227 if (pNodeA->IsBoundaryNode() || pNodeB->IsBoundaryNode()) 01228 { 01229 /* 01230 * In this case, the node configuration looks like: 01231 * 01232 * A B A B 01233 * \ / \ / 01234 * \ (1)/ \(1) / 01235 * (3) o--o (empty) or (empty) o--o (3) (element number in brackets) 01236 * / (2)\ /(2) \ 01237 * / \ / \ 01238 * 01239 * We perform a Type 1 swap in this case. 01240 */ 01241 PerformT1Swap(pNodeA, pNodeB, all_indices); 01242 } 01243 else 01244 { 01245 /* 01246 * In this case, the node configuration looks like: 01247 * 01248 * A B A B 01249 * \ / 01250 * \ (1) (1) / 01251 * (3) o--o--- or ---o--o (3) (element number in brackets) 01252 * / (2) (2) \ 01253 * / \ 01254 * 01255 * We should not be able to get here when running normal vertex code 01256 * as there should only be nodes on 3 way junctions or boundaries. 01257 */ 01258 01259 EXCEPTION("There are non-boundary nodes contained only in 2 elements something has gone wrong."); 01260 } 01261 } 01262 break; 01263 } 01264 case 4: 01265 { 01266 /* 01267 * In this case, the node configuration looks like: 01268 * 01269 * \(1)/ 01270 * \ / Node A 01271 * (2) | (4) (element number in brackets) 01272 * / \ Node B 01273 * /(3)\ 01274 * 01275 * We perform a Type 1 swap in this case. 01276 */ 01277 PerformT1Swap(pNodeA, pNodeB, all_indices); 01278 break; 01279 } 01280 default: 01281 // This can't happen 01282 NEVER_REACHED; 01283 } 01284 } 01285 } 01286 01287 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 01288 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::PerformNodeMerge(Node<SPACE_DIM>* pNodeA, Node<SPACE_DIM>* pNodeB) 01289 { 01290 // Sort the nodes by index 01291 unsigned nodeA_index = pNodeA->GetIndex(); 01292 unsigned nodeB_index = pNodeB->GetIndex(); 01293 01294 unsigned lo_node_index = (nodeA_index < nodeB_index) ? nodeA_index : nodeB_index; // low index 01295 unsigned hi_node_index = (nodeA_index < nodeB_index) ? nodeB_index : nodeA_index; // high index 01296 01297 // Get pointers to the nodes, sorted by index 01298 Node<SPACE_DIM>* p_lo_node = this->GetNode(lo_node_index); 01299 Node<SPACE_DIM>* p_hi_node = this->GetNode(hi_node_index); 01300 01301 // Find the sets of elements containing each of the nodes, sorted by index 01302 std::set<unsigned> lo_node_elem_indices = p_lo_node->rGetContainingElementIndices(); 01303 std::set<unsigned> hi_node_elem_indices = p_hi_node->rGetContainingElementIndices(); 01304 01305 // Move the low-index node to the mid-point 01306 c_vector<double, SPACE_DIM> node_midpoint = p_lo_node->rGetLocation() + 0.5*this->GetVectorFromAtoB(p_lo_node->rGetLocation(), p_hi_node->rGetLocation()); 01307 c_vector<double, SPACE_DIM>& r_lo_node_location = p_lo_node->rGetModifiableLocation(); 01308 r_lo_node_location = node_midpoint; 01309 01310 // Update the elements previously containing the high-index node to contain the low-index node 01311 for (std::set<unsigned>::const_iterator it = hi_node_elem_indices.begin(); 01312 it != hi_node_elem_indices.end(); 01313 ++it) 01314 { 01315 // Find the local index of the high-index node in this element 01316 unsigned hi_node_local_index = this->mElements[*it]->GetNodeLocalIndex(hi_node_index); 01317 assert(hi_node_local_index < UINT_MAX); // this element should contain the high-index node 01318 01319 /* 01320 * If this element already contains the low-index node, then just remove the high-index node. 01321 * Otherwise replace it with the low-index node in the element and remove it from mNodes. 01322 */ 01323 if (lo_node_elem_indices.count(*it) > 0) 01324 { 01325 this->mElements[*it]->DeleteNode(hi_node_local_index); // think this method removes the high-index node from mNodes 01326 } 01327 else 01328 { 01329 // Replace the high-index node with the low-index node in this element 01330 this->mElements[*it]->UpdateNode(hi_node_local_index, p_lo_node); 01331 } 01332 } 01333 assert(!(this->mNodes[hi_node_index]->IsDeleted())); 01334 this->mNodes[hi_node_index]->MarkAsDeleted(); 01335 mDeletedNodeIndices.push_back(hi_node_index); 01336 } 01337 01338 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 01339 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::PerformT1Swap(Node<SPACE_DIM>* pNodeA, 01340 Node<SPACE_DIM>* pNodeB, 01341 std::set<unsigned>& rElementsContainingNodes) 01342 { 01343 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 01344 assert(SPACE_DIM == 2); // only works in 2D at present 01345 assert(ELEMENT_DIM == SPACE_DIM); 01346 01347 /* 01348 * Restructure elements - remember to update nodes and elements. 01349 * 01350 * We need to implement the following changes: 01351 * 01352 * The element whose index was in nodeA_elem_indices but not nodeB_elem_indices, 01353 * and the element whose index was in nodeB_elem_indices but not nodeA_elem_indices, 01354 * should now both contain nodes A and B. 01355 * 01356 * The element whose index was in nodeA_elem_indices and nodeB_elem_indices, and which 01357 * node C lies inside, should now only contain node A. 01358 * 01359 * The element whose index was in nodeA_elem_indices and nodeB_elem_indices, and which 01360 * node D lies inside, should now only contain node B. 01361 * 01362 * Iterate over all elements involved and identify which element they are 01363 * in the diagram then update the nodes as necessary. 01364 * 01365 * \(1)/ 01366 * \ / Node A 01367 * (2) | (4) elements in brackets 01368 * / \ Node B 01369 * /(3)\ 01370 * 01371 */ 01372 01373 /* 01374 * Compute the locations of two new nodes C, D, placed on either side of the 01375 * edge E_old formed by nodes current_node and anticlockwise_node, such 01376 * that the edge E_new formed by the new nodes is the perpendicular bisector 01377 * of E_old, with |E_new| 'just larger' (mCellRearrangementRatio) than mThresholdDistance. 01378 */ 01379 01380 // Find the sets of elements containing nodes A and B 01381 std::set<unsigned> nodeA_elem_indices = pNodeA->rGetContainingElementIndices(); 01382 std::set<unsigned> nodeB_elem_indices = pNodeB->rGetContainingElementIndices(); 01383 01384 double distance_between_nodes_CD = mCellRearrangementRatio*mCellRearrangementThreshold; 01385 01386 c_vector<double, SPACE_DIM> nodeA_location = pNodeA->rGetLocation(); 01387 c_vector<double, SPACE_DIM> nodeB_location = pNodeB->rGetLocation(); 01388 01389 c_vector<double, SPACE_DIM> a_to_b = this->GetVectorFromAtoB(nodeA_location, nodeB_location); 01390 01391 // Store the location of the T1Swap, the mid point of the moving nodes, 01392 mLocationsOfT1Swaps.push_back(nodeA_location + 0.5*a_to_b); 01393 01394 c_vector<double, SPACE_DIM> perpendicular_vector; 01395 perpendicular_vector(0) = -a_to_b(1); 01396 perpendicular_vector(1) = a_to_b(0); 01397 01399 if (norm_2(a_to_b) < 1e-10) 01400 { 01401 EXCEPTION("Nodes are too close together, this shouldn't happen"); 01402 } 01403 01404 c_vector<double, SPACE_DIM> c_to_d = distance_between_nodes_CD / norm_2(a_to_b) * perpendicular_vector; 01405 c_vector<double, SPACE_DIM> nodeC_location = nodeA_location + 0.5*a_to_b - 0.5*c_to_d; 01406 c_vector<double, SPACE_DIM> nodeD_location = nodeC_location + c_to_d; 01407 01408 /* 01409 * Move node A to C and node B to D 01410 */ 01411 01412 c_vector<double, SPACE_DIM>& r_nodeA_location = pNodeA->rGetModifiableLocation(); 01413 r_nodeA_location = nodeC_location; 01414 01415 c_vector<double, SPACE_DIM>& r_nodeB_location = pNodeB->rGetModifiableLocation(); 01416 r_nodeB_location = nodeD_location; 01417 01418 for (std::set<unsigned>::const_iterator it = rElementsContainingNodes.begin(); 01419 it != rElementsContainingNodes.end(); 01420 ++it) 01421 { 01422 if (nodeA_elem_indices.find(*it) == nodeA_elem_indices.end()) // not in nodeA_elem_indices so element 3 01423 { 01424 /* 01425 * In this case the element index was not in 01426 * nodeA_elem_indices, so this element 01427 * does not contain node A. Therefore we must add node A 01428 * (which has been moved to node C) to this element. 01429 * 01430 * Locate local index of node B in element then add node A after 01431 * in anticlockwise direction. 01432 */ 01433 01434 unsigned nodeB_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeB->GetIndex()); 01435 assert(nodeB_local_index < UINT_MAX); // this element should contain node B 01436 01437 this->mElements[*it]->AddNode(pNodeA, nodeB_local_index); 01438 } 01439 else if (nodeB_elem_indices.find(*it) == nodeB_elem_indices.end()) // not in nodeB_elem_indices so element 1 01440 { 01441 /* 01442 * In this case the element index was not in 01443 * nodeB_elem_indices, so this element 01444 * does not contain node B. Therefore we must add node B 01445 * (which has been moved to node D) to this element. 01446 * 01447 * Locate local index of node A in element then add node B after 01448 * in anticlockwise direction. 01449 */ 01450 unsigned nodeA_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeA->GetIndex()); 01451 assert(nodeA_local_index < UINT_MAX); // this element should contain node A 01452 this->mElements[*it]->AddNode(pNodeB, nodeA_local_index); 01453 } 01454 else 01455 { 01456 /* 01457 * In this case the element index was in both nodeB_elem_indices and nodeB_elem_indices 01458 * so is element 2 or 4 01459 */ 01460 01461 /* 01462 * Locate local index of nodeA and nodeB and use the ordering to 01463 * identify the element, if nodeB_index > nodeA_index then element 4 01464 * and if nodeA_index > nodeB_index then element 2 01465 */ 01466 unsigned nodeA_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeA->GetIndex()); 01467 assert(nodeA_local_index < UINT_MAX); // this element should contain node A 01468 01469 unsigned nodeB_local_index = this->mElements[*it]->GetNodeLocalIndex(pNodeB->GetIndex()); 01470 assert(nodeB_local_index < UINT_MAX); // this element should contain node B 01471 01472 unsigned nodeB_local_index_plus_one = (nodeB_local_index + 1)%(this->mElements[*it]->GetNumNodes()); 01473 01474 if (nodeA_local_index == nodeB_local_index_plus_one) 01475 { 01476 /* 01477 * In this case the local index of nodeA is the local index of 01478 * nodeB plus one so we are in element 2 so we remove nodeB 01479 */ 01480 this->mElements[*it]->DeleteNode(nodeB_local_index); 01481 } 01482 else 01483 { 01484 assert(nodeB_local_index == (nodeA_local_index + 1)%(this->mElements[*it]->GetNumNodes())); // as A and B are next to each other 01485 /* 01486 * In this case the local index of nodeA is the local index of 01487 * nodeB minus one so we are in element 4 so we remove nodeA 01488 */ 01489 this->mElements[*it]->DeleteNode(nodeA_local_index); 01490 } 01491 } 01492 } 01493 01494 // Sort out boundary nodes 01495 if (pNodeA->IsBoundaryNode() || pNodeB->IsBoundaryNode()) 01496 { 01497 if (pNodeA->GetNumContainingElements()==3) 01498 { 01499 pNodeA->SetAsBoundaryNode(false); 01500 } 01501 else 01502 { 01503 pNodeA->SetAsBoundaryNode(true); 01504 } 01505 if (pNodeB->GetNumContainingElements()==3) 01506 { 01507 pNodeB->SetAsBoundaryNode(false); 01508 } 01509 else 01510 { 01511 pNodeB->SetAsBoundaryNode(true); 01512 } 01513 } 01514 } 01515 01516 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 01517 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::PerformIntersectionSwap(Node<SPACE_DIM>* pNode, unsigned elementIndex) 01518 { 01519 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 01520 assert(SPACE_DIM == 2); // only works in 2D at present 01521 assert(ELEMENT_DIM == SPACE_DIM); 01522 01523 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elementIndex); 01524 unsigned num_nodes = p_element->GetNumNodes(); 01525 01526 std::set<unsigned> elements_containing_intersecting_node; 01527 01528 for (unsigned node_local_index=0; node_local_index<num_nodes; node_local_index++) 01529 { 01530 unsigned node_global_index = p_element->GetNodeGlobalIndex(node_local_index); 01531 01532 std::set<unsigned> node_elem_indices = this->GetNode(node_global_index)->rGetContainingElementIndices(); 01533 01534 for (std::set<unsigned>::const_iterator elem_iter = node_elem_indices.begin(); 01535 elem_iter != node_elem_indices.end(); 01536 ++elem_iter) 01537 { 01538 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_neighboring_element = this->GetElement(*elem_iter); 01539 01540 // Check if element contains the intersecting node 01541 for (unsigned node_index_2 = 0; node_index_2 < p_neighboring_element->GetNumNodes(); node_index_2++) 01542 { 01543 if(p_neighboring_element->GetNodeGlobalIndex(node_index_2)==pNode->GetIndex()) 01544 { 01545 elements_containing_intersecting_node.insert(p_neighboring_element->GetIndex()); 01546 } 01547 } 01548 } 01549 } 01550 /* 01551 * If there are not 2 elements containing the intersecting node then the node is coming from the other side of the element 01552 * and there is no way to fix it unles you want to make 2 new elements. 01553 */ 01554 assert(elements_containing_intersecting_node.size()==2); 01555 01556 std::set<unsigned> all_elements_containing_intersecting_node = pNode->rGetContainingElementIndices(); 01557 01558 std::set<unsigned> intersecting_element; 01559 01560 std::set_difference( all_elements_containing_intersecting_node.begin(), all_elements_containing_intersecting_node.end(), 01561 elements_containing_intersecting_node.begin(), elements_containing_intersecting_node.end(), 01562 std::inserter(intersecting_element, intersecting_element.begin())); 01563 01564 /* 01565 * Identify nodes and Elements to perform switch on 01566 * Intersecting node is node A 01567 * Other node is node B 01568 * 01569 * Element 1 only contains node A 01570 * Element 2 has nodes B and A (in that order) 01571 * Element 3 only contains node B 01572 * Element 4 has nodes A and B (in that order) 01573 */ 01574 unsigned node_A_index = pNode->GetIndex(); 01575 unsigned node_B_index; 01576 unsigned element_1_index = *(intersecting_element.begin()); 01577 unsigned element_2_index; 01578 unsigned element_3_index = elementIndex; 01579 unsigned element_4_index; 01580 01581 std::set<unsigned>::iterator iter = elements_containing_intersecting_node.begin(); 01582 unsigned element_a_index = *(iter); 01583 iter++; 01584 unsigned element_b_index = *(iter); 01585 01586 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_a = this->GetElement(element_a_index); 01587 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_b = this->GetElement(element_b_index); 01588 01589 std::set<unsigned> element_a_nodes; 01590 for (unsigned node_index = 0; node_index < p_element_a->GetNumNodes(); node_index++) 01591 { 01592 element_a_nodes.insert(p_element_a->GetNodeGlobalIndex(node_index)); 01593 } 01594 01595 std::set<unsigned> element_b_nodes; 01596 for (unsigned node_index = 0; node_index < p_element_b->GetNumNodes(); node_index++) 01597 { 01598 element_b_nodes.insert(p_element_b->GetNodeGlobalIndex(node_index)); 01599 } 01600 01601 std::set<unsigned> switching_nodes; 01602 std::set_intersection(element_a_nodes.begin(), element_a_nodes.end(), 01603 element_b_nodes.begin(), element_b_nodes.end(), 01604 std::inserter(switching_nodes, switching_nodes.begin())); 01605 01606 assert(switching_nodes.size() == 2); 01607 01608 // Check intersecting node is this set 01609 assert(switching_nodes.find(node_A_index) != switching_nodes.end()); 01610 switching_nodes.erase(node_A_index); 01611 01612 assert(switching_nodes.size() == 1); 01613 01614 node_B_index = *(switching_nodes.begin()); 01615 01616 // Now identify elements 2 and 4 01617 unsigned node_A_local_index_in_a = p_element_a->GetNodeLocalIndex(node_A_index); 01618 unsigned node_B_local_index_in_a = p_element_a->GetNodeLocalIndex(node_B_index); 01619 01620 if ((node_B_local_index_in_a+1)%p_element_a->GetNumNodes() == node_A_local_index_in_a) 01621 { 01622 assert((p_element_b->GetNodeLocalIndex(node_A_index)+1)%p_element_b->GetNumNodes() 01623 == p_element_b->GetNodeLocalIndex(node_B_index)); 01624 01625 // Element 2 is element a, element 4 is element b 01626 element_2_index = element_a_index; 01627 element_4_index = element_b_index; 01628 } 01629 else 01630 { 01631 assert((p_element_b->GetNodeLocalIndex(node_B_index)+1)%p_element_b->GetNumNodes() 01632 == p_element_b->GetNodeLocalIndex(node_A_index)); 01633 01634 // Element 2 is element b, element 4 is element a 01635 element_2_index = element_b_index; 01636 element_4_index = element_a_index; 01637 } 01638 01639 unsigned intersected_edge = this->GetLocalIndexForElementEdgeClosestToPoint(pNode->rGetLocation(), elementIndex); 01640 01641 unsigned node_A_local_index_in_1 = this->GetElement(element_1_index)->GetNodeLocalIndex(node_A_index); 01642 01643 unsigned node_A_local_index_in_2 = this->GetElement(element_2_index)->GetNodeLocalIndex(node_A_index); 01644 unsigned node_B_local_index_in_2 = this->GetElement(element_2_index)->GetNodeLocalIndex(node_B_index); 01645 01646 unsigned node_B_local_index_in_3 = this->GetElement(elementIndex)->GetNodeLocalIndex(node_B_index); 01647 01648 unsigned node_A_local_index_in_4 = this->GetElement(element_4_index)->GetNodeLocalIndex(node_A_index); 01649 unsigned node_B_local_index_in_4 = this->GetElement(element_4_index)->GetNodeLocalIndex(node_B_index); 01650 01651 if (intersected_edge==node_B_local_index_in_3) 01652 { 01653 /* 01654 * Add node B to element 1 after node A 01655 * Add node A to element 3 after node B 01656 * 01657 * Remove node B from element 2 01658 * Remove node A from element 4 01659 */ 01660 this->mElements[element_1_index]->AddNode(this->mNodes[node_B_index], node_A_local_index_in_1); 01661 this->mElements[element_3_index]->AddNode(this->mNodes[node_A_index], node_B_local_index_in_3); 01662 01663 this->mElements[element_2_index]->DeleteNode(node_B_local_index_in_2); 01664 this->mElements[element_4_index]->DeleteNode(node_A_local_index_in_4); 01665 } 01666 else 01667 { 01668 assert((intersected_edge+1)%num_nodes==node_B_local_index_in_3); 01669 01670 /* 01671 * Add node B to element 1 before node A 01672 * Add node A to element 3 before node B 01673 * 01674 * Remove node A from element 2 01675 * Remove node B from element 4 01676 */ 01677 unsigned node_before_A_in_1 = (node_A_local_index_in_1 - 1)%this->GetElement(element_1_index)->GetNumNodes(); 01678 unsigned node_before_B_in_3 = (node_B_local_index_in_3 - 1)%this->GetElement(element_3_index)->GetNumNodes(); 01679 01680 this->mElements[element_1_index]->AddNode(this->mNodes[node_B_index], node_before_A_in_1); 01681 this->mElements[element_3_index]->AddNode(this->mNodes[node_A_index], node_before_B_in_3); 01682 01683 this->mElements[element_2_index]->DeleteNode(node_A_local_index_in_2); 01684 this->mElements[element_4_index]->DeleteNode(node_B_local_index_in_4); 01685 } 01686 } 01687 01688 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 01689 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::PerformT2Swap(VertexElement<ELEMENT_DIM,SPACE_DIM>& rElement) 01690 { 01691 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 01692 assert(SPACE_DIM == 2); // only works in 2D at present 01693 assert(ELEMENT_DIM == SPACE_DIM); 01694 01695 /* 01696 * For removing a small triangle 01697 * 01698 * \ 01699 * \ 01700 * |\ 01701 * | \ 01702 * | \_ _ _ _ _ 01703 * | / 01704 * | / 01705 * |/ 01706 * / 01707 * / 01708 * 01709 * To 01710 * 01711 * \ 01712 * \ 01713 * \ 01714 * \ 01715 * \_ _ _ _ _ 01716 * / 01717 * / 01718 * / 01719 * / 01720 * / 01721 * 01722 */ 01723 01724 // Assert that the triangle element has only three nodes (!) 01725 assert(rElement.GetNumNodes() == 3u); 01726 01727 bool is_node_on_boundary = false; 01728 for (unsigned i=0; i<3; i++) 01729 { 01730 if (rElement.GetNode(i)->IsBoundaryNode()) 01731 { 01732 is_node_on_boundary= true; 01733 } 01734 } 01735 01736 // Create new node at centroid of element which will be a boundary node if any of the existing nodes was on the boundary. 01737 c_vector<double, SPACE_DIM> new_node_location = this->GetCentroidOfElement(rElement.GetIndex()); 01738 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(GetNumNodes(), new_node_location, is_node_on_boundary)); 01739 Node<SPACE_DIM>* p_new_node = this->GetNode(new_node_global_index); 01740 01741 std::set<unsigned> neighbouring_elements; 01742 01743 for (unsigned i=0; i<3; i++) 01744 { 01745 Node<SPACE_DIM>* p_node_a = rElement.GetNode((i+1)%3); 01746 Node<SPACE_DIM>* p_node_b = rElement.GetNode((i+2)%3); 01747 01748 std::set<unsigned> elements_of_node_a = p_node_a->rGetContainingElementIndices(); 01749 std::set<unsigned> elements_of_node_b = p_node_b->rGetContainingElementIndices(); 01750 01751 std::set<unsigned> common_elements; 01752 01753 std::set_intersection( elements_of_node_a.begin(), elements_of_node_a.end(), 01754 elements_of_node_b.begin(), elements_of_node_b.end(), 01755 std::inserter(common_elements, common_elements.begin())); 01756 01757 assert(common_elements.size() <= 2u); 01758 common_elements.erase(rElement.GetIndex()); 01759 01760 if (common_elements.size() == 1u) // there is a neighbouring element 01761 { 01762 VertexElement<ELEMENT_DIM,SPACE_DIM>* p_neighbouring_element = this->GetElement(*(common_elements.begin())); 01763 01764 if (p_neighbouring_element->GetNumNodes() < 4u) 01765 { 01766 EXCEPTION("One of the neighbours of a small triangular element is also a triangle - dealing with this has not been implemented yet"); 01767 } 01768 01769 p_neighbouring_element-> ReplaceNode(p_node_a, p_new_node); 01770 p_neighbouring_element->DeleteNode(p_neighbouring_element->GetNodeLocalIndex(p_node_b->GetIndex())); 01771 } 01772 else 01773 { 01774 assert( (p_node_a->IsBoundaryNode()) && (p_node_b->IsBoundaryNode()) ); 01775 } 01776 } 01777 01778 // Also have to mark pElement, pElement->GetNode(0), pElement->GetNode(1), and pElement->GetNode(2) as deleted. 01779 mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(0)); 01780 mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(1)); 01781 mDeletedNodeIndices.push_back(rElement.GetNodeGlobalIndex(2)); 01782 rElement.GetNode(0)->MarkAsDeleted(); 01783 rElement.GetNode(1)->MarkAsDeleted(); 01784 rElement.GetNode(2)->MarkAsDeleted(); 01785 01786 mDeletedElementIndices.push_back(rElement.GetIndex()); 01787 rElement.MarkAsDeleted(); 01788 } 01789 01790 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 01791 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::PerformT3Swap(Node<SPACE_DIM>* pNode, unsigned elementIndex) 01792 { 01793 // Make sure that we are in the correct dimension - this code will be eliminated at compile time 01794 assert(SPACE_DIM == 2); // only works in 2D at present 01795 assert(ELEMENT_DIM == SPACE_DIM); 01796 01797 // Check pNode is a boundary node 01798 assert(pNode->IsBoundaryNode()); 01799 01800 // Store the index of the elements containing the intersecting node 01801 std::set<unsigned> elements_containing_intersecting_node = pNode->rGetContainingElementIndices(); 01802 01803 // Get the local index of the node in the intersected element after which the new node is to be added 01804 unsigned node_A_local_index = this->GetLocalIndexForElementEdgeClosestToPoint(pNode->rGetLocation(), elementIndex); 01805 01806 // Get current node location 01807 c_vector<double, SPACE_DIM> node_location = pNode->rGetModifiableLocation(); 01808 01809 // Get element 01810 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element = this->GetElement(elementIndex); 01811 unsigned num_nodes = p_element->GetNumNodes(); 01812 01814 // TRACE("intersecting node"); 01815 // PRINT_2_VARIABLES(pNode->GetIndex(),node_location); 01816 // 01817 // 01818 // for (std::set<unsigned>::const_iterator elem_iter = elements_containing_intersecting_node.begin(); 01819 // elem_iter != elements_containing_intersecting_node.end(); 01820 // elem_iter++) 01821 // 01822 // { 01823 // TRACE("intersecting element"); 01824 // 01825 // VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_intersection = this->GetElement(*elem_iter); 01826 // PRINT_VARIABLE(p_element_intersection->GetIndex()); 01827 // 01828 // for (unsigned node_index = 0; 01829 // node_index < p_element_intersection->GetNumNodes(); 01830 // node_index++) 01831 // { 01832 // PRINT_3_VARIABLES(p_element_intersection->GetNodeGlobalIndex(node_index), 01833 // p_element_intersection->GetNode(node_index)->IsBoundaryNode(), 01834 // p_element_intersection->GetNodeLocation(node_index)); 01835 // } 01836 // } 01837 // TRACE("intersected element"); 01838 // PRINT_VARIABLE(p_element->GetIndex()); 01839 // for (unsigned node_index = 0; 01840 // node_index < p_element->GetNumNodes(); 01841 // node_index++) 01842 // { 01843 // PRINT_3_VARIABLES(p_element->GetNodeGlobalIndex(node_index), 01844 // p_element->GetNode(node_index)->IsBoundaryNode(), 01845 // p_element->GetNodeLocation(node_index)); 01846 // } 01848 01849 // Get the nodes at either end of the edge to be divided 01850 unsigned vertexA_index = p_element->GetNodeGlobalIndex(node_A_local_index); 01851 unsigned vertexB_index = p_element->GetNodeGlobalIndex((node_A_local_index+1)%num_nodes); 01852 01853 // Check these nodes are also boundary nodes if this fails then the elements have become concave and you need a smaller timestep 01854 if (!this->mNodes[vertexA_index]->IsBoundaryNode() || !this->mNodes[vertexB_index]->IsBoundaryNode()) 01855 { 01856 EXCEPTION("A boundary node has intersected a non boundary edge, this is because the boundary element has become concave you need to rerun the simulation with a smaller time step to prevent this."); 01857 } 01858 01859 // Get the nodes at either end of the edge to be divided and calculate intersection 01860 c_vector<double, SPACE_DIM> vertexA = p_element->GetNodeLocation(node_A_local_index); 01861 c_vector<double, SPACE_DIM> vertexB = p_element->GetNodeLocation((node_A_local_index+1)%num_nodes); 01862 c_vector<double, SPACE_DIM> vector_a_to_point = this->GetVectorFromAtoB(vertexA, node_location); 01863 01864 c_vector<double, SPACE_DIM> vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB); 01865 01866 c_vector<double, SPACE_DIM> edge_ab_unit_vector = vector_a_to_b/norm_2(vector_a_to_b); 01867 c_vector<double, SPACE_DIM> intersection = vertexA + edge_ab_unit_vector*inner_prod(vector_a_to_point, edge_ab_unit_vector); 01868 01869 // Store the location of the T3Swap, the location of the intersection with the edge. 01870 mLocationsOfT3Swaps.push_back(intersection); 01871 01872 /* 01873 * If the edge is shorter than 4.0*mCellRearrangementRatio*mCellRearrangementThreshold move vertexA and vertexB 01874 * 4.0*mCellRearrangementRatio*mCellRearrangementThreshold apart. \todo investigate if moving A and B causes other issues with nearby nodes. 01875 * 01876 * Note: this distance so that there is always enough room for new nodes (if necessary) 01877 * \todo currently this assumes a worst case scenario of 3 nodes between A and B could be less movement for other cases. #1399 01878 */ 01879 if (norm_2(vector_a_to_b) < 4.0*mCellRearrangementRatio*mCellRearrangementThreshold) 01880 { 01881 WARNING("Trying to merge a node onto an edge which is too small."); 01882 01883 c_vector<double, SPACE_DIM> centre_a_and_b = vertexA + 0.5*vector_a_to_b; 01884 01885 vertexA = centre_a_and_b - 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*vector_a_to_b/norm_2(vector_a_to_b); 01886 ChastePoint<SPACE_DIM> vertex_A_point(vertexA); 01887 SetNode(p_element->GetNodeGlobalIndex(node_A_local_index), vertex_A_point); 01888 01889 vertexB = centre_a_and_b + 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*vector_a_to_b/norm_2(vector_a_to_b); 01890 ChastePoint<SPACE_DIM> vertex_B_point(vertexB); 01891 SetNode(p_element->GetNodeGlobalIndex((node_A_local_index+1)%num_nodes), vertex_B_point); 01892 01893 // Reset distances 01894 vector_a_to_b = this->GetVectorFromAtoB(vertexA, vertexB); 01895 edge_ab_unit_vector = vector_a_to_b/norm_2(vector_a_to_b); 01896 01897 // Reset the intersection to the middle to allow enough room for new nodes 01898 intersection = centre_a_and_b; 01899 } 01900 01901 /* 01902 * If the intersection is within mCellRearrangementRatio^2*mCellRearrangementThreshold of vertexA or vertexB move it 01903 * mCellRearrangementRatio^2*mCellRearrangementThreshold away. 01904 * 01905 * Note: this distance so that there is always enough room for new nodes (if necessary). 01906 * \todo currently this assumes a worst case scenario of 3 nodes between A and B could be less movement for other cases. 01907 */ 01908 if (norm_2(intersection - vertexA) < 2.0*mCellRearrangementRatio*mCellRearrangementThreshold) 01909 { 01910 intersection = vertexA + 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 01911 } 01912 if (norm_2(intersection - vertexB) < 2.0*mCellRearrangementRatio*mCellRearrangementThreshold) 01913 { 01914 intersection = vertexB - 2.0*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 01915 } 01916 01917 if (pNode->GetNumContainingElements() == 1) 01918 { 01919 // Get the index of the element containing the intersecting node 01920 unsigned intersecting_element_index = *elements_containing_intersecting_node.begin(); 01921 01922 // Get element 01923 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_intersecting_element = this->GetElement(intersecting_element_index); 01924 01925 unsigned local_index = p_intersecting_element->GetNodeLocalIndex(pNode->GetIndex()); 01926 unsigned next_node = p_intersecting_element->GetNodeGlobalIndex((local_index + 1)%(p_intersecting_element->GetNumNodes())); 01927 unsigned previous_node = p_intersecting_element->GetNodeGlobalIndex((local_index + p_intersecting_element->GetNumNodes() - 1)%(p_intersecting_element->GetNumNodes())); 01928 01929 // Check to see if the nodes adjacent to the intersecting node are contained in the intersected element VertexA and VertexB 01930 if (next_node == vertexA_index || previous_node == vertexA_index || next_node == vertexB_index || previous_node == vertexB_index) 01931 { 01932 unsigned common_vertex_index; 01933 01934 if (next_node == vertexA_index || previous_node == vertexA_index) 01935 { 01936 common_vertex_index = vertexA_index; 01937 } 01938 else 01939 { 01940 common_vertex_index = vertexB_index; 01941 } 01942 01943 assert(this->mNodes[common_vertex_index]->GetNumContainingElements()>1); 01944 01945 std::set<unsigned> elements_containing_common_vertex = this->mNodes[common_vertex_index]->rGetContainingElementIndices(); 01946 std::set<unsigned>::const_iterator it = elements_containing_common_vertex.begin(); 01947 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_1 = this->GetElement(*it); 01948 it++; 01949 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_2 = this->GetElement(*it); 01950 01951 // Calculate the number of common vertices between element_1 and element_2 01952 unsigned num_common_vertices = 0; 01953 for (unsigned i=0; i<p_element_common_1->GetNumNodes(); i++) 01954 { 01955 for (unsigned j=0; j<p_element_common_2->GetNumNodes(); j++) 01956 { 01957 if (p_element_common_1->GetNodeGlobalIndex(i)==p_element_common_2->GetNodeGlobalIndex(j)) 01958 { 01959 num_common_vertices++; 01960 } 01961 } 01962 } 01963 01964 if (num_common_vertices == 1 || this->mNodes[common_vertex_index]->GetNumContainingElements() > 2) 01965 { 01966 /* 01967 * This is the situation here. 01968 * 01969 * From To 01970 * _ _ 01971 * | <--- | 01972 * | /\ |\ 01973 * | / \ | \ 01974 * _|/____\ _|__\ 01975 * 01976 * The edge goes from vertexA--vertexB to vertexA--pNode--vertexB 01977 */ 01978 01979 // Move original node 01980 pNode->rGetModifiableLocation() = intersection; 01981 01982 // Add the moved nodes to the element (this also updates the node) 01983 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 01984 01985 // Check the nodes are updated correctly 01986 assert(pNode->GetNumContainingElements() == 2); 01987 } 01988 else if (num_common_vertices == 2) 01989 { 01990 /* 01991 * This is the situation here. 01992 * 01993 * C is common_vertex D is the other one. 01994 * 01995 * From To 01996 * _ D _ 01997 * | <--- | 01998 * | /\ |\ 01999 * C|/ \ | \ 02000 * _|____\ _|__\ 02001 * 02002 * The edge goes from vertexC--vertexB to vertexC--pNode--vertexD 02003 * then VertexB is removed as it is no longer needed. 02004 */ 02005 02006 // Move original node 02007 pNode->rGetModifiableLocation() = intersection; 02008 02009 // Replace common_vertex with the the moved node (this also updates the nodes) 02010 this->GetElement(elementIndex)->ReplaceNode(this->mNodes[common_vertex_index], pNode); 02011 02012 // Remove common_vertex 02013 unsigned common_vertex_local_index = this->GetElement(intersecting_element_index)->GetNodeLocalIndex(common_vertex_index); 02014 this->GetElement(intersecting_element_index)->DeleteNode(common_vertex_local_index); 02015 assert(this->mNodes[common_vertex_index]->GetNumContainingElements() == 0); 02016 02017 this->mNodes[common_vertex_index]->MarkAsDeleted(); 02018 mDeletedNodeIndices.push_back(common_vertex_index); 02019 02020 // Check the nodes are updated correctly 02021 assert(pNode->GetNumContainingElements() == 2); 02022 } 02023 else 02024 { 02025 // This can't happen as nodes can't be on the internal edge of 2 elements. 02026 NEVER_REACHED; 02027 } 02028 } 02029 else 02030 { 02031 /* 02032 * From To 02033 * ____ _______ 02034 * / \ 02035 * /\ ^ / \ 02036 * / \ | 02037 * 02038 * The edge goes from vertexA--vertexB to vertexA--new_node--pNode--vertexB 02039 */ 02040 02041 // Move original node 02042 pNode->rGetModifiableLocation() = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02043 02044 c_vector<double, SPACE_DIM> new_node_location = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02045 02046 // Add new node which will always be a boundary node 02047 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1])); 02048 02049 // Add the moved and new nodes to the element (this also updates the node) 02050 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02051 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index); 02052 02053 // Add the new node to the original element containing pNode (this also updates the node) 02054 this->GetElement(intersecting_element_index)->AddNode(this->mNodes[new_node_global_index], this->GetElement(intersecting_element_index)->GetNodeLocalIndex(pNode->GetIndex())); 02055 02056 // Check the nodes are updated correctly 02057 assert(pNode->GetNumContainingElements() == 2); 02058 assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2); 02059 } 02060 } 02061 else if (pNode->GetNumContainingElements() == 2) 02062 { 02063 // Find the nodes contained in elements containing the intersecting node 02064 std::set<unsigned>::const_iterator it = elements_containing_intersecting_node.begin(); 02065 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_intersection_1 = this->GetElement(*it); 02066 it++; 02067 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_intersection_2 = this->GetElement(*it); 02068 02069 unsigned local_index_1 = p_element_intersection_1->GetNodeLocalIndex(pNode->GetIndex()); 02070 unsigned next_node_1 = p_element_intersection_1->GetNodeGlobalIndex((local_index_1 + 1)%(p_element_intersection_1->GetNumNodes())); 02071 unsigned previous_node_1 = p_element_intersection_1->GetNodeGlobalIndex((local_index_1 + p_element_intersection_1->GetNumNodes() - 1)%(p_element_intersection_1->GetNumNodes())); 02072 unsigned local_index_2 = p_element_intersection_2->GetNodeLocalIndex(pNode->GetIndex()); 02073 unsigned next_node_2 = p_element_intersection_2->GetNodeGlobalIndex((local_index_2 + 1)%(p_element_intersection_2->GetNumNodes())); 02074 unsigned previous_node_2 = p_element_intersection_2->GetNodeGlobalIndex((local_index_2 + p_element_intersection_2->GetNumNodes() - 1)%(p_element_intersection_2->GetNumNodes())); 02075 02076 // Check to see if the nodes adjacent to the intersecting node are contained in the intersected element VertexA and VertexB 02077 if ((next_node_1 == vertexA_index || previous_node_1 == vertexA_index || next_node_2 == vertexA_index || previous_node_2 == vertexA_index) && 02078 (next_node_1 == vertexB_index || previous_node_1 == vertexB_index || next_node_2 == vertexB_index || previous_node_2 == vertexB_index)) 02079 { 02080 /* 02081 * Here we have 02082 * __ 02083 * /| / 02084 * __ / | --> ___/ 02085 * \ | \ 02086 * \|__ \ 02087 * 02088 * Where the node on the left has overlapped the edge A B 02089 * 02090 * Move p_node to the intersection on A B and merge AB and p_node 02091 */ 02092 02093 //Check they are all boundary nodes 02094 assert(pNode->IsBoundaryNode()); 02095 assert(this->mNodes[vertexA_index]->IsBoundaryNode()); 02096 assert(this->mNodes[vertexB_index]->IsBoundaryNode()); 02097 02098 // Move p_node to the intersection with the edge A B 02099 pNode->rGetModifiableLocation() = intersection; 02100 pNode->SetAsBoundaryNode(false); 02101 02102 // Add pNode to the intersected element 02103 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02104 02105 // Remove VertexA from elements 02106 std::set<unsigned> elements_containing_vertex_A = this->mNodes[vertexA_index]->rGetContainingElementIndices(); 02107 for (std::set<unsigned>::const_iterator iter = elements_containing_vertex_A.begin(); 02108 iter != elements_containing_vertex_A.end(); 02109 iter++) 02110 { 02111 this->GetElement(*iter)->DeleteNode(this->GetElement(*iter)->GetNodeLocalIndex(vertexA_index)); 02112 } 02113 02114 // Remove VertexA from the mesh 02115 assert(this->mNodes[vertexA_index]->GetNumContainingElements()==0); 02116 02117 this->mNodes[vertexA_index]->MarkAsDeleted(); 02118 mDeletedNodeIndices.push_back(vertexA_index); 02119 02120 // Remove VertexB from elements 02121 std::set<unsigned> elements_containing_vertex_B = this->mNodes[vertexB_index]->rGetContainingElementIndices(); 02122 for (std::set<unsigned>::const_iterator iter = elements_containing_vertex_B.begin(); 02123 iter != elements_containing_vertex_B.end(); 02124 iter++) 02125 { 02126 this->GetElement(*iter)->DeleteNode(this->GetElement(*iter)->GetNodeLocalIndex(vertexB_index)); 02127 } 02128 02129 // Remove VertexB from the mesh 02130 assert(this->mNodes[vertexB_index]->GetNumContainingElements()==0); 02131 02132 this->mNodes[vertexB_index]->MarkAsDeleted(); 02133 mDeletedNodeIndices.push_back(vertexB_index); 02134 } 02135 else 02136 { 02137 if (next_node_1 == vertexA_index || previous_node_1 == vertexA_index || next_node_2 == vertexA_index || previous_node_2 == vertexA_index) 02138 { 02139 // Get elements containing vertexA_index (the Common vertex) 02140 02141 assert(this->mNodes[vertexA_index]->GetNumContainingElements()>1); 02142 02143 std::set<unsigned> elements_containing_vertex_A = this->mNodes[vertexA_index]->rGetContainingElementIndices(); 02144 std::set<unsigned>::const_iterator iter = elements_containing_vertex_A.begin(); 02145 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_1 = this->GetElement(*iter); 02146 iter++; 02147 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_2 = this->GetElement(*iter); 02148 02149 // Calculate the number of common vertices between element_1 and element_2 02150 unsigned num_common_vertices = 0; 02151 for (unsigned i=0; i<p_element_common_1->GetNumNodes(); i++) 02152 { 02153 for (unsigned j=0; j<p_element_common_2->GetNumNodes(); j++) 02154 { 02155 if (p_element_common_1->GetNodeGlobalIndex(i) == p_element_common_2->GetNodeGlobalIndex(j)) 02156 { 02157 num_common_vertices++; 02158 } 02159 } 02160 } 02161 02162 if (num_common_vertices == 1 || this->mNodes[vertexA_index]->GetNumContainingElements() > 2) 02163 { 02164 /* 02165 * From To 02166 * _ B _ B 02167 * | <--- | 02168 * | /|\ |\ 02169 * | / | \ | \ 02170 * | / | \ |\ \ 02171 * _|/___|___\ _|_\_\ 02172 * A A 02173 * 02174 * The edge goes from vertexA--vertexB to vertexA--pNode--new_node--vertexB 02175 */ 02176 02177 // Move original node and change to non-boundary node 02178 pNode->rGetModifiableLocation() = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02179 pNode->SetAsBoundaryNode(false); 02180 02181 c_vector<double, SPACE_DIM> new_node_location = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02182 02183 // Add new node which will always be a boundary node 02184 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1])); 02185 02186 // Add the moved nodes to the element (this also updates the node) 02187 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index); 02188 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02189 02190 // Add the new nodes to the original elements containing pNode (this also updates the node) 02191 if (next_node_1 == previous_node_2) 02192 { 02193 p_element_intersection_1->AddNode(this->mNodes[new_node_global_index], (local_index_1 + p_element_intersection_1->GetNumNodes() - 1)%(p_element_intersection_1->GetNumNodes())); 02194 } 02195 else 02196 { 02197 assert(next_node_2 == previous_node_1); 02198 02199 p_element_intersection_2->AddNode(this->mNodes[new_node_global_index], (local_index_2 + p_element_intersection_2->GetNumNodes() - 1)%(p_element_intersection_2->GetNumNodes())); 02200 } 02201 02202 // Check the nodes are updated correctly 02203 assert(pNode->GetNumContainingElements() == 3); 02204 assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2); 02205 } 02206 else if (num_common_vertices == 2) 02207 { 02208 /* 02209 * From To 02210 * _ B _ B 02211 * |<--- | 02212 * | /|\ |\ 02213 * |/ | \ | \ 02214 * | | \ |\ \ 02215 * _|__|___\ _|_\_\ 02216 * A A 02217 * 02218 * The edge goes from vertexA--vertexB to vertexA--pNode--new_node--vertexB 02219 * then vertexA is removed 02220 */ 02221 02222 // Move original node and change to non-boundary node 02223 pNode->rGetModifiableLocation() = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02224 pNode->SetAsBoundaryNode(false); 02225 02226 c_vector<double, SPACE_DIM> new_node_location = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02227 02228 // Add new node which will always be a boundary node 02229 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1])); 02230 02231 // Add the moved nodes to the element (this also updates the node) 02232 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index); 02233 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02234 02235 // Add the new nodes to the original elements containing pNode (this also updates the node) 02236 if (next_node_1 == previous_node_2) 02237 { 02238 p_element_intersection_1->AddNode(this->mNodes[new_node_global_index], (local_index_1 + p_element_intersection_1->GetNumNodes() - 1)%(p_element_intersection_1->GetNumNodes())); 02239 } 02240 else 02241 { 02242 assert(next_node_2 == previous_node_1); 02243 02244 p_element_intersection_2->AddNode(this->mNodes[new_node_global_index], (local_index_2 + p_element_intersection_2->GetNumNodes() - 1)%(p_element_intersection_2->GetNumNodes())); 02245 } 02246 02247 // Remove VertexA from the mesh 02248 p_element_common_1->DeleteNode(p_element_common_1->GetNodeLocalIndex(vertexA_index)); 02249 p_element_common_2->DeleteNode(p_element_common_2->GetNodeLocalIndex(vertexA_index)); 02250 02251 assert(this->mNodes[vertexA_index]->GetNumContainingElements()==0); 02252 02253 this->mNodes[vertexA_index]->MarkAsDeleted(); 02254 mDeletedNodeIndices.push_back(vertexA_index); 02255 02256 // Check the nodes are updated correctly 02257 assert(pNode->GetNumContainingElements() == 3); 02258 assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2); 02259 } 02260 else 02261 { 02262 // This can't happen as nodes can't be on the internal edge of 2 elements. 02263 NEVER_REACHED; 02264 } 02265 02266 } 02267 else if (next_node_1 == vertexB_index || previous_node_1 == vertexB_index || next_node_2 == vertexB_index || previous_node_2 == vertexB_index) 02268 { 02269 // Get elements containing vertexB_index (the Common vertex) 02270 02271 assert(this->mNodes[vertexB_index]->GetNumContainingElements()>1); 02272 02273 std::set<unsigned> elements_containing_vertex_B = this->mNodes[vertexB_index]->rGetContainingElementIndices(); 02274 std::set<unsigned>::const_iterator iter = elements_containing_vertex_B.begin(); 02275 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_1 = this->GetElement(*iter); 02276 iter++; 02277 VertexElement<ELEMENT_DIM, SPACE_DIM>* p_element_common_2 = this->GetElement(*iter); 02278 02279 // Calculate the number of common vertices between element_1 and element_2 02280 unsigned num_common_vertices = 0; 02281 for (unsigned i=0; i<p_element_common_1->GetNumNodes(); i++) 02282 { 02283 for (unsigned j=0; j<p_element_common_2->GetNumNodes(); j++) 02284 { 02285 if (p_element_common_1->GetNodeGlobalIndex(i)==p_element_common_2->GetNodeGlobalIndex(j)) 02286 { 02287 num_common_vertices++; 02288 } 02289 } 02290 } 02291 02292 if (num_common_vertices == 1 || this->mNodes[vertexB_index]->GetNumContainingElements() > 2) 02293 { 02294 /* 02295 * From To 02296 * _B_________ _B____ 02297 * |\ | / | / / 02298 * | \ | / |/ / 02299 * | \ | / | / 02300 * | \|/ |/ 02301 * _| <--- _| 02302 * A 02303 * 02304 * The edge goes from vertexA--vertexB to vertexA--new_node--pNode--vertexB 02305 */ 02306 02307 // Move original node and change to non-boundary node 02308 pNode->rGetModifiableLocation() = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02309 pNode->SetAsBoundaryNode(false); 02310 02311 c_vector<double, SPACE_DIM> new_node_location = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02312 02313 // Add new node which will always be a boundary node 02314 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1])); 02315 02316 // Add the moved nodes to the element (this also updates the node) 02317 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02318 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index); 02319 02320 // Add the new nodes to the original elements containing pNode (this also updates the node) 02321 if (next_node_1 == previous_node_2) 02322 { 02323 p_element_intersection_2->AddNode(this->mNodes[new_node_global_index], local_index_2); 02324 } 02325 else 02326 { 02327 assert(next_node_2 == previous_node_1); 02328 02329 p_element_intersection_1->AddNode(this->mNodes[new_node_global_index], local_index_1); 02330 } 02331 02332 // Check the nodes are updated correctly 02333 assert(pNode->GetNumContainingElements() == 3); 02334 assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2); 02335 } 02336 else if (num_common_vertices == 2) 02337 { 02338 /* 02339 * From To 02340 * _B_______ _B____ 02341 * | | / | / / 02342 * | | / |/ / 02343 * |\ | / | / 02344 * | \|/ |/ 02345 * _| <--- _| 02346 * A 02347 * 02348 * The edge goes from vertexA--vertexB to vertexA--new_node--pNode--vertexB 02349 * then vertexB is removed 02350 */ 02351 02352 // Move original node and change to non-boundary node 02353 pNode->rGetModifiableLocation() = intersection + 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02354 pNode->SetAsBoundaryNode(false); 02355 02356 c_vector<double, SPACE_DIM> new_node_location = intersection - 0.5*mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02357 02358 // Add new node which will always be a boundary node 02359 unsigned new_node_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_location[0], new_node_location[1])); 02360 02361 // Add the moved nodes to the element (this also updates the node) 02362 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02363 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_global_index], node_A_local_index); 02364 02365 // Add the new nodes to the original elements containing pNode (this also updates the node) 02366 if (next_node_1 == previous_node_2) 02367 { 02368 p_element_intersection_2->AddNode(this->mNodes[new_node_global_index], local_index_2); 02369 } 02370 else 02371 { 02372 assert(next_node_2 == previous_node_1); 02373 02374 p_element_intersection_1->AddNode(this->mNodes[new_node_global_index], local_index_1); 02375 } 02376 02377 // Remove VertexB from the mesh 02378 p_element_common_1->DeleteNode(p_element_common_1->GetNodeLocalIndex(vertexB_index)); 02379 p_element_common_2->DeleteNode(p_element_common_2->GetNodeLocalIndex(vertexB_index)); 02380 02381 assert(this->mNodes[vertexB_index]->GetNumContainingElements()==0); 02382 02383 this->mNodes[vertexB_index]->MarkAsDeleted(); 02384 mDeletedNodeIndices.push_back(vertexB_index); 02385 02386 // Check the nodes are updated correctly 02387 assert(pNode->GetNumContainingElements() == 3); 02388 assert(this->mNodes[new_node_global_index]->GetNumContainingElements() == 2); 02389 } 02390 else 02391 { 02392 // This can't happen as nodes can't be on the internal edge of 2 elements. 02393 NEVER_REACHED; 02394 } 02395 } 02396 else 02397 { 02398 /* 02399 * From To 02400 * _____ _______ 02401 * / | \ 02402 * /|\ ^ / | \ 02403 * / | \ | 02404 * 02405 * The edge goes from vertexA--vertexB to vertexA--new_node_1--pNode--new_node_2--vertexB 02406 */ 02407 02408 // Move original node and change to non-boundary node 02409 pNode->rGetModifiableLocation() = intersection; 02410 pNode->SetAsBoundaryNode(false); 02411 02412 c_vector<double, SPACE_DIM> new_node_1_location = intersection - mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02413 c_vector<double, SPACE_DIM> new_node_2_location = intersection + mCellRearrangementRatio*mCellRearrangementThreshold*edge_ab_unit_vector; 02414 02415 // Add new nodes which will always be boundary nodes 02416 unsigned new_node_1_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_1_location[0], new_node_1_location[1])); 02417 unsigned new_node_2_global_index = this->AddNode(new Node<SPACE_DIM>(0, true, new_node_2_location[0], new_node_2_location[1])); 02418 02419 // Add the moved and new nodes to the element (this also updates the node) 02420 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_2_global_index], node_A_local_index); 02421 this->GetElement(elementIndex)->AddNode(pNode, node_A_local_index); 02422 this->GetElement(elementIndex)->AddNode(this->mNodes[new_node_1_global_index], node_A_local_index); 02423 02424 // Add the new nodes to the original elements containing pNode (this also updates the node) 02425 if (next_node_1 == previous_node_2) 02426 { 02427 p_element_intersection_1->AddNode(this->mNodes[new_node_2_global_index], (local_index_1 + p_element_intersection_1->GetNumNodes() - 1)%(p_element_intersection_1->GetNumNodes())); 02428 p_element_intersection_2->AddNode(this->mNodes[new_node_1_global_index], local_index_2); 02429 } 02430 else 02431 { 02432 assert(next_node_2 == previous_node_1); 02433 02434 p_element_intersection_1->AddNode(this->mNodes[new_node_1_global_index], local_index_1); 02435 p_element_intersection_2->AddNode(this->mNodes[new_node_2_global_index], (local_index_2 + p_element_intersection_2->GetNumNodes() - 1)%(p_element_intersection_2->GetNumNodes())); 02436 } 02437 02438 // Check the nodes are updated correctly 02439 assert(pNode->GetNumContainingElements() == 3); 02440 assert(this->mNodes[new_node_1_global_index]->GetNumContainingElements() == 2); 02441 assert(this->mNodes[new_node_2_global_index]->GetNumContainingElements() == 2); 02442 } 02443 } 02444 } 02445 else 02446 { 02447 EXCEPTION("Trying to merge a node, contained in more than 2 elements, into another element, this is not possible with the vertex mesh."); 02448 } 02449 } 02450 02451 template<unsigned ELEMENT_DIM, unsigned SPACE_DIM> 02452 void MutableVertexMesh<ELEMENT_DIM, SPACE_DIM>::PerformVoidRemoval(Node<SPACE_DIM>* pNodeA, Node<SPACE_DIM>* pNodeB, Node<SPACE_DIM>* pNodeC) 02453 { 02454 unsigned nodeA_index = pNodeA->GetIndex(); 02455 unsigned nodeB_index = pNodeB->GetIndex(); 02456 unsigned nodeC_index = pNodeC->GetIndex(); 02457 02458 c_vector<double, SPACE_DIM> nodes_midpoint = pNodeA->rGetLocation() + this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeB->rGetLocation())/3.0 02459 + this->GetVectorFromAtoB(pNodeA->rGetLocation(), pNodeC->rGetLocation())/3.0; 02460 02461 Node<SPACE_DIM>* p_low_node_A_B = (nodeA_index < nodeB_index) ? pNodeA : pNodeB; // Node with the lowest index out of A and B 02462 Node<SPACE_DIM>* p_low_node = (p_low_node_A_B->GetIndex() < nodeC_index) ? p_low_node_A_B : pNodeC; // Node with the lowest index out of A, B and C. 02463 PerformNodeMerge(pNodeA,pNodeB); 02464 PerformNodeMerge(p_low_node_A_B,pNodeC); 02465 02466 c_vector<double, SPACE_DIM>& r_low_node_location = p_low_node->rGetModifiableLocation(); 02467 02468 r_low_node_location = nodes_midpoint; 02469 02470 // Sort out boundary nodes 02471 p_low_node->SetAsBoundaryNode(false); 02472 02473 // Remove the deleted nodes and re-index 02474 RemoveDeletedNodes(); 02475 } 02476 02478 // Explicit instantiation 02480 02481 template class MutableVertexMesh<1,1>; 02482 template class MutableVertexMesh<1,2>; 02483 template class MutableVertexMesh<1,3>; 02484 template class MutableVertexMesh<2,2>; 02485 template class MutableVertexMesh<2,3>; 02486 template class MutableVertexMesh<3,3>; 02487 02488 // Serialization for Boost >= 1.36 02489 #include "SerializationExportWrapperForCpp.hpp" 02490 EXPORT_TEMPLATE_CLASS_ALL_DIMS(MutableVertexMesh);