Cylindrical2dMesh.cpp

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