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 <map> 00037 00038 /* These lines are very useful for debugging (visualize with 'showme'). 00039 #include "TrianglesMeshWriter.hpp" 00040 TrianglesMeshWriter<2,2> mesh_writer("Cylindrical2dMeshDebug", "mesh", false); 00041 mesh_writer.WriteFilesUsingMesh(*this); 00042 */ 00043 #include "Cylindrical2dMesh.hpp" 00044 #include "Exception.hpp" 00045 00046 Cylindrical2dMesh::Cylindrical2dMesh(double width) 00047 : MutableMesh<2,2>(), 00048 mWidth(width) 00049 { 00050 assert(width > 0.0); 00051 } 00052 00053 Cylindrical2dMesh::~Cylindrical2dMesh() 00054 { 00055 } 00056 00057 Cylindrical2dMesh::Cylindrical2dMesh(double width, std::vector<Node<2>* > nodes) 00058 : MutableMesh<2,2>(), 00059 mWidth(width) 00060 { 00061 assert(width > 0.0); 00062 // mMismatchedBoundaryElements = false; 00063 for (unsigned index=0; index<nodes.size(); index++) 00064 { 00065 Node<2>* p_temp_node = nodes[index]; 00066 double x = p_temp_node->rGetLocation()[0]; 00067 x = x; // Fix optimised build 00068 assert( 0 <= x && x < width); 00069 mNodes.push_back(p_temp_node); 00070 } 00071 00072 NodeMap node_map(nodes.size()); 00073 ReMesh(node_map); 00074 } 00075 00076 //bool Cylindrical2dMesh::GetInstanceOfMismatchedBoundaryNodes() 00077 //{ 00078 // return mMismatchedBoundaryElements; 00079 //} 00080 00081 void Cylindrical2dMesh::UpdateTopAndBottom() 00082 { 00083 ChasteCuboid<2> bounding_box = CalculateBoundingBox(); 00084 mBottom = bounding_box.rGetLowerCorner()[1]; 00085 mTop = bounding_box.rGetUpperCorner()[1]; 00086 } 00087 00088 void Cylindrical2dMesh::CreateMirrorNodes() 00089 { 00090 double half_way = 0.5*mWidth; 00091 00092 mLeftOriginals.clear(); 00093 mLeftImages.clear(); 00094 mImageToLeftOriginalNodeMap.clear(); 00095 mRightOriginals.clear(); 00096 mRightImages.clear(); 00097 mImageToRightOriginalNodeMap.clear(); 00098 mLeftPeriodicBoundaryElementIndices.clear(); 00099 mRightPeriodicBoundaryElementIndices.clear(); 00100 00101 for (AbstractMesh<2,2>::NodeIterator node_iter = GetNodeIteratorBegin(); 00102 node_iter != GetNodeIteratorEnd(); 00103 ++node_iter) 00104 { 00105 c_vector<double, 2> location = node_iter->rGetLocation(); 00106 unsigned this_node_index = node_iter->GetIndex(); 00107 double this_node_x_location = location[0]; 00108 00109 // Check the mesh currently conforms to the dimensions given 00110 assert(0.0 <= location[0]); 00111 assert(location[0] <= mWidth); 00112 00113 // Put the nodes which are to be mirrored in the relevant vectors 00114 if (this_node_x_location < half_way) 00115 { 00116 mLeftOriginals.push_back(this_node_index); 00117 } 00118 else 00119 { 00120 mRightOriginals.push_back(this_node_index); 00121 } 00122 } 00123 00124 // For each left original node, create an image node and record its new index 00125 for (unsigned i=0; i<mLeftOriginals.size(); i++) 00126 { 00127 c_vector<double, 2> location = mNodes[mLeftOriginals[i]]->rGetLocation(); 00128 location[0] = location[0] + mWidth; 00129 00130 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location)); 00131 mLeftImages.push_back(new_node_index); 00132 mImageToLeftOriginalNodeMap[new_node_index] = mLeftOriginals[i]; 00133 } 00134 00135 // For each right original node, create an image node and record its new index 00136 for (unsigned i=0; i<mRightOriginals.size(); i++) 00137 { 00138 c_vector<double, 2> location = mNodes[mRightOriginals[i]]->rGetLocation(); 00139 location[0] = location[0] - mWidth; 00140 00141 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location)); 00142 mRightImages.push_back(new_node_index); 00143 mImageToRightOriginalNodeMap[new_node_index] = mRightOriginals[i]; 00144 } 00145 00146 assert(mRightOriginals.size() == mRightImages.size()); 00147 assert(mLeftOriginals.size() == mLeftImages.size()); 00148 assert(mImageToLeftOriginalNodeMap.size() == mLeftOriginals.size()); 00149 assert(mImageToRightOriginalNodeMap.size() == mRightOriginals.size()); 00150 } 00151 00152 void Cylindrical2dMesh::CreateHaloNodes() 00153 { 00154 UpdateTopAndBottom(); 00155 00156 mTopHaloNodes.clear(); 00157 mBottomHaloNodes.clear(); 00158 00159 unsigned num_halo_nodes = (unsigned)(floor(mWidth*2.0)); 00160 double halo_node_separation = mWidth/((double)(num_halo_nodes)); 00161 double y_top_coordinate = mTop + halo_node_separation; 00162 double y_bottom_coordinate = mBottom - halo_node_separation; 00163 00164 c_vector<double, 2> location; 00165 for (unsigned i=0; i<num_halo_nodes; i++) 00166 { 00167 double x_coordinate = 0.5*halo_node_separation + (double)(i)*halo_node_separation; 00168 00169 // Inserting top halo node in mesh 00170 location[0] = x_coordinate; 00171 location[1] = y_top_coordinate; 00172 unsigned new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location)); 00173 mTopHaloNodes.push_back(new_node_index); 00174 00175 location[1] = y_bottom_coordinate; 00176 new_node_index = MutableMesh<2,2>::AddNode(new Node<2>(0, location)); 00177 mBottomHaloNodes.push_back(new_node_index); 00178 } 00179 } 00180 00181 void Cylindrical2dMesh::ReMesh(NodeMap& rMap) 00182 { 00183 unsigned old_num_all_nodes = GetNumAllNodes(); 00184 00185 rMap.Resize(old_num_all_nodes); 00186 rMap.ResetToIdentity(); 00187 00188 // Flag the deleted nodes as deleted in the map 00189 for (unsigned i=0; i<old_num_all_nodes; i++) 00190 { 00191 if (mNodes[i]->IsDeleted()) 00192 { 00193 rMap.SetDeleted(i); 00194 } 00195 } 00196 00197 CreateHaloNodes(); 00198 00199 // Create mirrored nodes for the normal remesher to work with 00200 CreateMirrorNodes(); 00201 00202 /* 00203 * The mesh now has messed up boundary elements, but this 00204 * doesn't matter as the ReMesh() below doesn't read them in 00205 * and reconstructs the boundary elements. 00206 * 00207 * Call ReMesh() on the parent class. Note that the mesh now has lots 00208 * of extra nodes which will be deleted, hence the name 'big_map'. 00209 */ 00210 NodeMap big_map(GetNumAllNodes()); 00211 MutableMesh<2,2>::ReMesh(big_map); 00212 00213 /* 00214 * If the big_map isn't the identity map, the little map ('map') needs to be 00215 * altered accordingly before being passed to the user. Not sure how this all 00216 * works, so deal with this bridge when we get to it. 00217 */ 00218 assert(big_map.IsIdentityMap()); 00219 00220 // Re-index the vectors according to the big nodemap, and set up the maps. 00221 mImageToLeftOriginalNodeMap.clear(); 00222 mImageToRightOriginalNodeMap.clear(); 00223 00224 assert(mLeftOriginals.size() == mLeftImages.size()); 00225 assert(mRightOriginals.size() == mRightImages.size()); 00226 00227 for (unsigned i=0; i<mLeftOriginals.size(); i++) 00228 { 00229 mLeftOriginals[i] = big_map.GetNewIndex(mLeftOriginals[i]); 00230 mLeftImages[i] = big_map.GetNewIndex(mLeftImages[i]); 00231 mImageToLeftOriginalNodeMap[mLeftImages[i]] = mLeftOriginals[i]; 00232 } 00233 00234 for (unsigned i=0; i<mRightOriginals.size(); i++) 00235 { 00236 mRightOriginals[i] = big_map.GetNewIndex(mRightOriginals[i]); 00237 mRightImages[i] = big_map.GetNewIndex(mRightImages[i]); 00238 mImageToRightOriginalNodeMap[mRightImages[i]] = mRightOriginals[i]; 00239 } 00240 00241 for (unsigned i=0; i<mTopHaloNodes.size(); i++) 00242 { 00243 mTopHaloNodes[i] = big_map.GetNewIndex(mTopHaloNodes[i]); 00244 mBottomHaloNodes[i] = big_map.GetNewIndex(mBottomHaloNodes[i]); 00245 } 00246 00247 /* 00248 * Check that elements crossing the periodic boundary have been meshed 00249 * in the same way at each side. 00250 */ 00251 CorrectNonPeriodicMesh(); 00252 00253 /* 00254 * Take the double-sized mesh, with its new boundary elements, and 00255 * remove the relevant nodes, elements and boundary elements to leave 00256 * a proper periodic mesh. 00257 */ 00258 ReconstructCylindricalMesh(); 00259 00260 DeleteHaloNodes(); 00261 00262 /* 00263 * Create a random boundary element between two nodes of the first 00264 * element if it is not deleted. This is a temporary measure to get 00265 * around re-index crashing when there are no boundary elements. 00266 */ 00267 unsigned num_elements = GetNumAllElements(); 00268 bool boundary_element_made = false; 00269 unsigned elem_index = 0; 00270 00271 while (elem_index<num_elements && !boundary_element_made) 00272 { 00273 Element<2,2>* p_element = GetElement(elem_index); 00274 if (!p_element->IsDeleted()) 00275 { 00276 boundary_element_made = true; 00277 std::vector<Node<2>*> nodes; 00278 nodes.push_back(p_element->GetNode(0)); 00279 nodes.push_back(p_element->GetNode(1)); 00280 BoundaryElement<1,2>* p_boundary_element = new BoundaryElement<1,2>(0, nodes); 00281 p_boundary_element->RegisterWithNodes(); 00282 mBoundaryElements.push_back(p_boundary_element); 00283 this->mBoundaryElementWeightedDirections.push_back(zero_vector<double>(2)); 00284 this->mBoundaryElementJacobianDeterminants.push_back(0.0); 00285 } 00286 elem_index++; 00287 } 00288 00289 // Now call ReIndex() to remove the temporary nodes which are marked as deleted 00290 NodeMap reindex_map(GetNumAllNodes()); 00291 ReIndex(reindex_map); 00292 assert(!reindex_map.IsIdentityMap()); // maybe don't need this 00293 00294 /* 00295 * Go through the reindex map and use it to populate the original NodeMap 00296 * (the one that is returned to the user). 00297 */ 00298 for (unsigned i=0; i<rMap.Size(); i++) // only going up to be size of map, not size of reindex_map 00299 { 00300 if (reindex_map.IsDeleted(i)) 00301 { 00302 /* 00303 * i < num_original_nodes and node is deleted, this should correspond to 00304 * a node that was labelled as before the remeshing, so should have already 00305 * been set as deleted in the map above. 00306 */ 00307 assert(rMap.IsDeleted(i)); 00308 } 00309 else 00310 { 00311 rMap.SetNewIndex(i, reindex_map.GetNewIndex(i)); 00312 } 00313 } 00314 00315 // We can now clear the index vectors and maps; they are only used for remeshing 00316 mLeftOriginals.clear(); 00317 mLeftImages.clear(); 00318 mImageToLeftOriginalNodeMap.clear(); 00319 mRightOriginals.clear(); 00320 mRightImages.clear(); 00321 mImageToRightOriginalNodeMap.clear(); 00322 mLeftPeriodicBoundaryElementIndices.clear(); 00323 mRightPeriodicBoundaryElementIndices.clear(); 00324 } 00325 00326 void Cylindrical2dMesh::ReconstructCylindricalMesh() 00327 { 00328 /* 00329 * Figure out which elements have real nodes and image nodes in them 00330 * and replace image nodes with corresponding real ones. 00331 */ 00332 for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin(); 00333 elem_iter != GetElementIteratorEnd(); 00334 ++elem_iter) 00335 { 00336 // Left images are on the right of the mesh 00337 unsigned number_of_left_image_nodes = 0; 00338 unsigned number_of_right_image_nodes = 0; 00339 00340 for (unsigned i=0; i<3; i++) 00341 { 00342 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i); 00343 00344 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end()) 00345 { 00346 number_of_left_image_nodes++; 00347 } 00348 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end()) 00349 { 00350 number_of_right_image_nodes++; 00351 } 00352 } 00353 00354 // Delete all the elements on the left hand side (images of right)... 00355 if (number_of_right_image_nodes >= 1) 00356 { 00357 elem_iter->MarkAsDeleted(); 00358 mDeletedElementIndices.push_back(elem_iter->GetIndex()); 00359 } 00360 00361 // Delete only purely imaginary elements on the right (images of left nodes) 00362 if (number_of_left_image_nodes == 3) 00363 { 00364 elem_iter->MarkAsDeleted(); 00365 mDeletedElementIndices.push_back(elem_iter->GetIndex()); 00366 } 00367 00368 /* 00369 * If some are images then replace them with the real nodes. There 00370 * can be elements with either two image nodes on the right (and one 00371 * real) or one image node on the right (and two real). 00372 */ 00373 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) 00374 { 00375 for (unsigned i=0; i<3; i++) 00376 { 00377 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i); 00378 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index); 00379 if (it != mImageToLeftOriginalNodeMap.end()) 00380 { 00381 elem_iter->ReplaceNode(mNodes[this_node_index], mNodes[it->second]); 00382 } 00383 } 00384 } 00385 } 00386 00387 /* 00388 * Figure out which boundary elements have real nodes and image nodes in them 00389 * and replace image nodes with corresponding real ones. 00390 */ 00391 for (unsigned elem_index = 0; elem_index<GetNumAllBoundaryElements(); elem_index++) 00392 { 00393 BoundaryElement<1,2>* p_boundary_element = GetBoundaryElement(elem_index); 00394 if (!p_boundary_element->IsDeleted()) 00395 { 00396 unsigned number_of_image_nodes = 0; 00397 for (unsigned i=0; i<2; i++) 00398 { 00399 unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i); 00400 00401 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end()) 00402 { 00403 number_of_image_nodes++; 00404 } 00405 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end()) 00406 { 00407 number_of_image_nodes++; 00408 } 00409 } 00410 00411 if (number_of_image_nodes == 2) 00412 { 00413 p_boundary_element->MarkAsDeleted(); 00414 mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex()); 00415 } 00416 00417 /* 00418 * To avoid having two copies of the boundary elements on the periodic 00419 * boundaries we only deal with the elements on the left image and 00420 * delete the ones on the right image. 00421 */ 00422 if (number_of_image_nodes == 1) 00423 { 00424 for (unsigned i=0; i<2; i++) 00425 { 00426 unsigned this_node_index = p_boundary_element->GetNodeGlobalIndex(i); 00427 std::map<unsigned, unsigned>::iterator it = mImageToLeftOriginalNodeMap.find(this_node_index); 00428 if (it != mImageToLeftOriginalNodeMap.end()) 00429 { 00430 p_boundary_element->ReplaceNode(mNodes[this_node_index], mNodes[it->second]); 00431 } 00432 else 00433 { 00434 it = mImageToRightOriginalNodeMap.find(this_node_index); 00435 if (it != mImageToRightOriginalNodeMap.end()) 00436 { 00437 p_boundary_element->MarkAsDeleted(); 00438 mDeletedBoundaryElementIndices.push_back(p_boundary_element->GetIndex()); 00439 } 00440 } 00441 } 00442 } 00443 } 00444 } 00445 00446 // Delete all image nodes unless they have already gone (halo nodes) 00447 for (unsigned i=0; i<mLeftImages.size(); i++) 00448 { 00449 mNodes[mLeftImages[i]]->MarkAsDeleted(); 00450 mDeletedNodeIndices.push_back(mLeftImages[i]); 00451 } 00452 00453 for (unsigned i=0; i<mRightImages.size(); i++) 00454 { 00455 mNodes[mRightImages[i]]->MarkAsDeleted(); 00456 mDeletedNodeIndices.push_back(mRightImages[i]); 00457 } 00458 } 00459 00460 void Cylindrical2dMesh::DeleteHaloNodes() 00461 { 00462 assert(mTopHaloNodes.size() == mBottomHaloNodes.size()); 00463 for (unsigned i=0; i<mTopHaloNodes.size(); i++) 00464 { 00465 DeleteBoundaryNodeAt(mTopHaloNodes[i]); 00466 DeleteBoundaryNodeAt(mBottomHaloNodes[i]); 00467 } 00468 } 00469 00470 c_vector<double, 2> Cylindrical2dMesh::GetVectorFromAtoB(const c_vector<double, 2>& rLocation1, const c_vector<double, 2>& rLocation2) 00471 { 00472 assert(mWidth > 0.0); 00473 00474 c_vector<double, 2> location1 = rLocation1; 00475 c_vector<double, 2> location2 = rLocation2; 00476 00477 location1[0] = fmod(location1[0], mWidth); 00478 location2[0] = fmod(location2[0], mWidth); 00479 00480 c_vector<double, 2> vector = location2 - location1; 00481 00482 /* 00483 * Handle the cylindrical condition here: if the points are more 00484 * than halfway around the cylinder apart, measure the other way. 00485 */ 00486 if (vector[0] > 0.5*mWidth) 00487 { 00488 vector[0] -= mWidth; 00489 } 00490 else if (vector[0] < -0.5*mWidth) 00491 { 00492 vector[0] += mWidth; 00493 } 00494 return vector; 00495 } 00496 00497 void Cylindrical2dMesh::SetNode(unsigned index, ChastePoint<2> point, bool concreteMove) 00498 { 00499 // Perform a periodic movement if necessary 00500 if (point.rGetLocation()[0] >= mWidth) 00501 { 00502 // Move point to the left 00503 point.SetCoordinate(0, point.rGetLocation()[0] - mWidth); 00504 } 00505 else if (point.rGetLocation()[0] < 0.0) 00506 { 00507 // Move point to the right 00508 point.SetCoordinate(0, point.rGetLocation()[0] + mWidth); 00509 } 00510 00511 // Update the node's location 00512 MutableMesh<2,2>::SetNode(index, point, concreteMove); 00513 } 00514 00515 double Cylindrical2dMesh::GetWidth(const unsigned& rDimension) const 00516 { 00517 double width = 0.0; 00518 assert(rDimension==0 || rDimension==1); 00519 if (rDimension==0) 00520 { 00521 width = mWidth; 00522 } 00523 else 00524 { 00525 width = MutableMesh<2,2>::GetWidth(rDimension); 00526 } 00527 return width; 00528 } 00529 00530 unsigned Cylindrical2dMesh::AddNode(Node<2>* pNewNode) 00531 { 00532 unsigned node_index = MutableMesh<2,2>::AddNode(pNewNode); 00533 00534 // If necessary move it to be back on the cylinder 00535 ChastePoint<2> new_node_point = pNewNode->GetPoint(); 00536 SetNode(node_index, new_node_point, false); 00537 00538 return node_index; 00539 } 00540 00541 void Cylindrical2dMesh::CorrectNonPeriodicMesh() 00542 { 00543 GenerateVectorsOfElementsStraddlingPeriodicBoundaries(); 00544 00545 /* 00546 * Copy the member variables into new vectors, which we modify 00547 * by knocking out elements which pair up on each side. 00548 */ 00549 std::set<unsigned> temp_left_hand_side_elements = mLeftPeriodicBoundaryElementIndices; 00550 std::set<unsigned> temp_right_hand_side_elements = mRightPeriodicBoundaryElementIndices; 00551 00552 // if ( (mLeftPeriodicBoundaryElementIndices.size()!=mRightPeriodicBoundaryElementIndices.size()) 00553 // || (temp_left_hand_side_elements.size() <= 2) 00554 // || (temp_right_hand_side_elements.size() <= 2) ) 00555 // { 00556 // mMismatchedBoundaryElements = true; 00557 // } 00558 assert(mLeftPeriodicBoundaryElementIndices.size()==mRightPeriodicBoundaryElementIndices.size()); 00559 00560 // Go through all of the elements on the left periodic boundary 00561 for (std::set<unsigned>::iterator left_iter = mLeftPeriodicBoundaryElementIndices.begin(); 00562 left_iter != mLeftPeriodicBoundaryElementIndices.end(); 00563 ++left_iter) 00564 { 00565 unsigned elem_index = *left_iter; 00566 00567 Element<2,2>* p_element = GetElement(elem_index); 00568 00569 /* 00570 * Make lists of the nodes which the elements on the left contain and 00571 * the nodes which should be in a corresponding element on the right. 00572 */ 00573 c_vector<unsigned,3> original_element_node_indices; 00574 c_vector<unsigned,3> corresponding_element_node_indices; 00575 for (unsigned i=0; i<3; i++) 00576 { 00577 original_element_node_indices[i] = p_element->GetNodeGlobalIndex(i); 00578 corresponding_element_node_indices[i] = GetCorrespondingNodeIndex(original_element_node_indices[i]); 00579 } 00580 00581 // Search the right hand side elements for the corresponding element 00582 for (std::set<unsigned>::iterator right_iter = mRightPeriodicBoundaryElementIndices.begin(); 00583 right_iter != mRightPeriodicBoundaryElementIndices.end(); 00584 ++right_iter) 00585 { 00586 unsigned corresponding_elem_index = *right_iter; 00587 00588 Element<2,2>* p_corresponding_element = GetElement(corresponding_elem_index); 00589 00590 bool is_corresponding_node = true; 00591 00592 for (unsigned i=0; i<3; i++) 00593 { 00594 if ( (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(0)) && 00595 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(1)) && 00596 (corresponding_element_node_indices[i] != p_corresponding_element->GetNodeGlobalIndex(2)) ) 00597 { 00598 is_corresponding_node = false; 00599 break; 00600 } 00601 } 00602 00603 if (is_corresponding_node) 00604 { 00605 // Remove original and corresponding element from sets 00606 temp_left_hand_side_elements.erase(elem_index); 00607 temp_right_hand_side_elements.erase(corresponding_elem_index); 00608 } 00609 } 00610 } 00611 00612 /* 00613 * If either of these ever throw you have more than one situation where the mesher has an option 00614 * of how to mesh. If it does ever throw you need to be cleverer and match up the 00615 * elements into as many pairs as possible on the left hand and right hand sides. 00616 */ 00617 // assert(temp_left_hand_side_elements.size() <= 2); 00618 // assert(temp_right_hand_side_elements.size() <= 2); 00619 00620 /* 00621 * Now we just have to use the first pair of elements and copy their info over to the other side. 00622 * First we need to get hold of both elements on either side. 00623 */ 00624 if (temp_left_hand_side_elements.empty() || temp_right_hand_side_elements.empty()) 00625 { 00626 assert(temp_right_hand_side_elements.empty()); 00627 assert(temp_left_hand_side_elements.empty()); 00628 } 00629 else 00630 { 00631 if (temp_right_hand_side_elements.size() == 2 && temp_left_hand_side_elements.size() == 2) 00632 { 00633 00634 if (temp_right_hand_side_elements.size() == 2) 00635 { 00636 // Use the right hand side meshing and map to left 00637 UseTheseElementsToDecideMeshing(temp_right_hand_side_elements); 00638 } 00639 else 00640 { 00641 /* 00642 * If you get here there are more than two mixed up elements on the periodic edge. 00643 * We need to knock the pair out and then rerun this function. This shouldn't be 00644 * too hard to do but is as yet unnecessary. 00645 */ 00646 NEVER_REACHED; 00647 } 00648 } 00649 } 00650 } 00651 00652 void Cylindrical2dMesh::UseTheseElementsToDecideMeshing(std::set<unsigned>& rMainSideElements) 00653 { 00654 assert(rMainSideElements.size() == 2); 00655 00656 // We find the four nodes surrounding the dodgy meshing, on each side. 00657 std::set<unsigned> main_four_nodes; 00658 for (std::set<unsigned>::iterator left_iter = rMainSideElements.begin(); 00659 left_iter != rMainSideElements.end(); 00660 ++left_iter) 00661 { 00662 unsigned elem_index = *left_iter; 00663 Element<2,2>* p_element = GetElement(elem_index); 00664 for (unsigned i=0; i<3; i++) 00665 { 00666 unsigned index = p_element->GetNodeGlobalIndex(i); 00667 main_four_nodes.insert(index); 00668 } 00669 } 00670 assert(main_four_nodes.size() == 4); 00671 00672 std::set<unsigned> other_four_nodes; 00673 for (std::set<unsigned>::iterator iter = main_four_nodes.begin(); 00674 iter != main_four_nodes.end(); 00675 ++iter) 00676 { 00677 other_four_nodes.insert(GetCorrespondingNodeIndex(*iter)); 00678 } 00679 assert(other_four_nodes.size() == 4); 00680 00681 /* 00682 * Find the elements surrounded by the nodes on the right 00683 * and change them to match the elements on the left. 00684 */ 00685 std::vector<unsigned> corresponding_elements; 00686 00687 // Loop over all elements 00688 for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin(); 00689 elem_iter != GetElementIteratorEnd(); 00690 ++elem_iter) 00691 { 00692 // Loop over the nodes of the element 00693 if (!(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(0))==other_four_nodes.end()) && 00694 !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(1))==other_four_nodes.end()) && 00695 !(other_four_nodes.find(elem_iter->GetNodeGlobalIndex(2))==other_four_nodes.end()) ) 00696 { 00697 corresponding_elements.push_back(elem_iter->GetIndex()); 00698 elem_iter->MarkAsDeleted(); 00699 mDeletedElementIndices.push_back(elem_iter->GetIndex()); 00700 } 00701 } 00702 assert(corresponding_elements.size() == 2); 00703 00704 // Now corresponding_elements contains the two elements which are going to be replaced by rMainSideElements 00705 unsigned num_elements = GetNumAllElements(); 00706 for (std::set<unsigned>::iterator iter = rMainSideElements.begin(); 00707 iter != rMainSideElements.end(); 00708 ++iter) 00709 { 00710 Element<2,2>* p_main_element = GetElement(*iter); 00711 std::vector<Node<2>*> nodes; 00712 00713 // Put corresponding nodes into a std::vector 00714 for (unsigned i=0; i<3; i++) 00715 { 00716 unsigned main_node = p_main_element->GetNodeGlobalIndex(i); 00717 nodes.push_back(this->GetNode(GetCorrespondingNodeIndex(main_node))); 00718 } 00719 00720 // Make a new element 00721 Element<2,2>* p_new_element = new Element<2,2>(num_elements, nodes); 00722 this->mElements.push_back(p_new_element); 00723 this->mElementJacobians.push_back(zero_matrix<double>(2,2)); 00724 this->mElementInverseJacobians.push_back(zero_matrix<double>(2,2)); 00725 this->mElementJacobianDeterminants.push_back(0.0); 00726 num_elements++; 00727 } 00728 00729 // Reindex to get rid of extra elements indices 00730 NodeMap map(GetNumAllNodes()); 00731 this->ReIndex(map); 00732 } 00733 00734 void Cylindrical2dMesh::GenerateVectorsOfElementsStraddlingPeriodicBoundaries() 00735 { 00736 mLeftPeriodicBoundaryElementIndices.clear(); 00737 mRightPeriodicBoundaryElementIndices.clear(); 00738 00739 unsigned incidences_of_zero_left_image_nodes = 0; 00740 unsigned incidences_of_zero_right_image_nodes = 0; 00741 00742 for (MutableMesh<2,2>::ElementIterator elem_iter = GetElementIteratorBegin(); 00743 elem_iter != GetElementIteratorEnd(); 00744 ++elem_iter) 00745 { 00746 // Left images are on the right of the mesh 00747 unsigned number_of_left_image_nodes = 0; 00748 unsigned number_of_right_image_nodes = 0; 00749 00750 for (unsigned i=0; i<3; i++) 00751 { 00752 unsigned this_node_index = elem_iter->GetNodeGlobalIndex(i); 00753 00754 if (mImageToLeftOriginalNodeMap.find(this_node_index) != mImageToLeftOriginalNodeMap.end()) 00755 { 00756 number_of_left_image_nodes++; 00757 } 00758 else if (mImageToRightOriginalNodeMap.find(this_node_index) != mImageToRightOriginalNodeMap.end()) 00759 { 00760 number_of_right_image_nodes++; 00761 } 00762 } 00763 00764 if ( (number_of_left_image_nodes == 0) && (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2) ) 00765 { 00766 incidences_of_zero_left_image_nodes++; 00767 } 00768 if ( (number_of_right_image_nodes == 0) && (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) ) 00769 { 00770 incidences_of_zero_right_image_nodes++; 00771 } 00772 00773 /* SJ - Have checked the following: 00774 * - It is never the case that number_of_left_image_nodes + number_of_right_image_nodes > 3 00775 * - There are 1264 incidences of zero left image nodes, and 1252 incidences of zero right image nodes 00776 * - There are 450 incidences of zero left image nodes and non-zero right image nodes; 438 incidences of zero right image nodes and non-zero left 00777 * image nodes 00778 * - There are 40 incidences of 0 left image nodes, and 1/2 right image nodes; 39 incidences of 0 right image nodes and 1/2 left image nodes 00779 * As this corresponds to 40 left-hand boundary elements and 39 right-hand boundary elements, then it is this extra occurrence of a 0 left 00780 * image node with 1/2 right image nodes that is responsible for the extra element. 00781 */ 00782 00783 // Elements on the left hand side (images of right nodes) 00784 if (number_of_right_image_nodes == 1 || number_of_right_image_nodes == 2) 00785 { 00786 mLeftPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex()); 00787 } 00788 00789 // Elements on the right (images of left nodes) 00790 if (number_of_left_image_nodes == 1 || number_of_left_image_nodes == 2) 00791 { 00792 mRightPeriodicBoundaryElementIndices.insert(elem_iter->GetIndex()); 00793 } 00794 } 00795 00796 // if (mLeftPeriodicBoundaryElementIndices.size() != mRightPeriodicBoundaryElementIndices.size()) 00797 // { 00798 // mMismatchedBoundaryElements = true; 00799 // // In here - if you hit this case, we want to stop the test and move on, so we work with a stopping event 00800 // 00801 // } 00802 00803 // Every boundary element on the left must have a corresponding element on the right 00804 assert(mLeftPeriodicBoundaryElementIndices.size() == mRightPeriodicBoundaryElementIndices.size()); 00805 } 00806 00807 unsigned Cylindrical2dMesh::GetCorrespondingNodeIndex(unsigned nodeIndex) 00808 { 00809 unsigned corresponding_node_index = UINT_MAX; 00810 00811 // If nodeIndex is a member of mRightOriginals, then find the corresponding node index in mRightImages 00812 std::vector<unsigned>::iterator right_orig_iter = std::find(mRightOriginals.begin(), mRightOriginals.end(), nodeIndex); 00813 if (right_orig_iter != mRightOriginals.end()) 00814 { 00815 corresponding_node_index = mRightImages[right_orig_iter - mRightOriginals.begin()]; 00816 } 00817 else 00818 { 00819 // If nodeIndex is a member of mRightImages, then find the corresponding node index in mRightOriginals 00820 std::vector<unsigned>::iterator right_im_iter = std::find(mRightImages.begin(), mRightImages.end(), nodeIndex); 00821 if (right_im_iter != mRightImages.end()) 00822 { 00823 corresponding_node_index = mRightOriginals[right_im_iter - mRightImages.begin()]; 00824 } 00825 else 00826 { 00827 // If nodeIndex is a member of mLeftOriginals, then find the corresponding node index in mLeftImages 00828 std::vector<unsigned>::iterator left_orig_iter = std::find(mLeftOriginals.begin(), mLeftOriginals.end(), nodeIndex); 00829 if (left_orig_iter != mLeftOriginals.end()) 00830 { 00831 corresponding_node_index = mLeftImages[left_orig_iter - mLeftOriginals.begin()]; 00832 } 00833 else 00834 { 00835 // If nodeIndex is a member of mLeftImages, then find the corresponding node index in mLeftOriginals 00836 std::vector<unsigned>::iterator left_im_iter = std::find(mLeftImages.begin(), mLeftImages.end(), nodeIndex); 00837 if (left_im_iter != mLeftImages.end()) 00838 { 00839 corresponding_node_index = mLeftOriginals[left_im_iter - mLeftImages.begin()]; 00840 } 00841 } 00842 } 00843 } 00844 00845 // We must have found the corresponding node index 00846 assert(corresponding_node_index != UINT_MAX); 00847 return corresponding_node_index; 00848 } 00849 00850 // Serialization for Boost >= 1.36 00851 #include "SerializationExportWrapperForCpp.hpp" 00852 CHASTE_CLASS_EXPORT(Cylindrical2dMesh)